在 C 中转换指针的规则是什么? [英] What are the rules for casting pointers in C?

查看:32
本文介绍了在 C 中转换指针的规则是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

K&R 没有仔细研究它,但他们使用它.我试着通过编写一个示例程序来看看它是如何工作的,但它并没有那么顺利:

K&R doesn't go over it, but they use it. I tried seeing how it'd work by writing an example program, but it didn't go so well:

#include <stdio.h> 
int bleh (int *); 

int main(){
    char c = '5'; 
    char *d = &c;

    bleh((int *)d); 
    return 0;  
}

int bleh(int *n){
    printf("%d bleh
", *n); 
    return *n; 
}

它可以编译,但我的打印语句会吐出垃圾变量(每次我调用程序时它们都不同).有任何想法吗?

It compiles, but my print statement spits out garbage variables (they're different every time I call the program). Any ideas?

推荐答案

在考虑指针时,绘制图表很有帮助.指针是指向内存中地址的箭头,带有指示值类型的标签.地址表示去哪里看,类型表示要拿什么.投射指针会更改箭头上的标签,但不会更改箭头指向的位置.

When thinking about pointers, it helps to draw diagrams. A pointer is an arrow that points to an address in memory, with a label indicating the type of the value. The address indicates where to look and the type indicates what to take. Casting the pointer changes the label on the arrow but not where the arrow points.

d 是指向 c 的指针,类型为 char.char 是一个字节的内存,所以当 d 被取消引用时,你会得到那一字节内存中的值.在下图中,每个单元格代表一个字节.

d in main is a pointer to c which is of type char. A char is one byte of memory, so when d is dereferenced, you get the value in that one byte of memory. In the diagram below, each cell represents one byte.

-+----+----+----+----+----+----+-
 |    | c  |    |    |    |    | 
-+----+----+----+----+----+----+-
       ^~~~
       | char
       d

当您将 d 转换为 int* 时,您是在说 d 确实指向一个 int价值.在当今大多数系统上,int 占用 4 个字节.

When you cast d to int*, you're saying that d really points to an int value. On most systems today, an int occupies 4 bytes.

-+----+----+----+----+----+----+-
 |    | c  | ?₁ | ?₂ | ?₃ |    | 
-+----+----+----+----+----+----+-
       ^~~~~~~~~~~~~~~~~~~
       | int
       (int*)d

当您取消引用 (int*)d 时,您将获得一个由这四个字节的内存确定的值.您获得的值取决于这些标记为 ? 的单元格中的内容,以及 int 在内存中的表示方式.

When you dereference (int*)d, you get a value that is determined from these four bytes of memory. The value you get depends on what is in these cells marked ?, and on how an int is represented in memory.

PC 是 little-endian,这意味着 int 的值是以这种方式计算(假设它跨越 4 个字节):* ((int*)d) == c + ?₁ * 2⁸ + ?₂ * 2¹⁶ + ?₃ * 2²⁴.所以你会看到,虽然值是垃圾,但如果你以十六进制打印 (printf("%x ", *n)),最后两位数字总是 35(即字符'5'的值).

A PC is little-endian, which means that the value of an int is calculated this way (assuming that it spans 4 bytes): * ((int*)d) == c + ?₁ * 2⁸ + ?₂ * 2¹⁶ + ?₃ * 2²⁴. So you'll see that while the value is garbage, if you print in in hexadecimal (printf("%x ", *n)), the last two digits will always be 35 (that's the value of the character '5').

其他一些系统是 big-endian 并将字节排列在另一个方向:* ((int*)d) == c * 2²⁴ + ?₁ * 2¹⁶ + ?₂ * 2⁸ + ?₃.在这些系统上,当以十六进制打印时,您会发现该值总是 starts35.某些系统的 int 大小不同于 4 个字节.少数系统以不同的方式排列 int,但您极不可能遇到它们.

Some other systems are big-endian and arrange the bytes in the other direction: * ((int*)d) == c * 2²⁴ + ?₁ * 2¹⁶ + ?₂ * 2⁸ + ?₃. On these systems, you'd find that the value always starts with 35 when printed in hexadecimal. Some systems have a size of int that's different from 4 bytes. A rare few systems arrange int in different ways but you're extremely unlikely to encounter them.

根据您的编译器和操作系统,您可能会发现每次运行程序时该值都不同,或者当您对源代码进行微小调整时它总是相同但会发生变化.

Depending on your compiler and operating system, you may find that the value is different every time you run the program, or that it's always the same but changes when you make even minor tweaks to the source code.

在某些系统上,int 值必须存储在 4(或 2、或 8)的倍数的地址中.这称为对齐要求.根据c的地址是否正确对齐,程序可能会崩溃.

On some systems, an int value must be stored in an address that's a multiple of 4 (or 2, or 8). This is called an alignment requirement. Depending on whether the address of c happens to be properly aligned or not, the program may crash.

与您的程序相反,当您拥有一个 int 值并获取指向它的指针时,会发生以下情况.

In contrast with your program, here's what happens when you have an int value and take a pointer to it.

int x = 42;
int *p = &x;

-+----+----+----+----+----+----+-
 |    |         x         |    | 
-+----+----+----+----+----+----+-
       ^~~~~~~~~~~~~~~~~~~
       | int
       p

指针p 指向一个int 值.箭头上的标签正确地描述了内存单元中的内容,因此在取消引用时不会出现意外.

The pointer p points to an int value. The label on the arrow correctly describes what's in the memory cell, so there are no surprises when dereferencing it.

这篇关于在 C 中转换指针的规则是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆