在C中转换为指针类型时发生了什么?

时间:2017-06-20 18:27:52

标签: c pointers casting

我已经看到NULL等价于(void*)0。但我不明白为什么零需要被void*括起来。当我们做这样的事情时,真正发生的事情

int *p = (int*)10;

(int*)是否在上述语句中将整数10的地址空间(占用4个字节)扩展为8个字节?

2 个答案:

答案 0 :(得分:4)

有几种方法可以回答这个问题。

我们说指针值是内存位置的地址。但是不同的计算机对内存使用了不同的寻址方案。 C是一种可以跨多种计算机移植的高级语言。 C不强制要求特定的内存架构。就C编程语言而言,内存地址实际上可能就像“123 Fourth Ave.”之类的东西,很难想象在整数和地址之间来回转换。

现在,对于您可能使用的任何机器,内存实际上是以一种相当简单且不令人惊讶的方式线性处理的。如果你的程序有1,000个字节的可用内存,那些字节的地址可能在0到999之间。所以如果你说

char *cp = (char *)10;

你只是设置一个指向位于地址10的字节的指针(或者,即程序地址空间中的第11个字节)。

现在,在C中,指针不仅仅是内存中某个位置的原始地址。在C中,还声明了一个指针,用于指定它指向的数据类型。所以,如果我们说

int *ip = (int *)10;

我们正在设置指向位于地址10的一个int的数据的指针。它与内存中的cp指向的点相同,但由于它是一个int指针,它将访问一个int的值字节,而不是cp之类的一个字节。如果我们在旧的16位机器上,并且int是两个字节,我们可以将ip视为指向地址空间中的第五个int。

C中的强制转换实际上可以做两件事:(1)转换值(“更改位”),或(2)更改值的解释。如果我们说float f = (float)3;,我们将在3的整数表示和3的浮点表示之间进行转换,这可能是完全不同的。如果我们向另一个方向前进,有int i = (int)3.14;之类的东西,我们也会扔掉小数部分,所以还有更多的转换。但是如果我们说int *ip = (int *)10;,我们实际上并没有对值10做任何事情,我们只是将它重新解释为指针。如果我们说char *cp = (char *)ip,我们又不会改变任何东西,我们只是重新解释一种不同的指针。

但是,我不得不补充说,我在这里所说的关于指针转换的所有内容都是(a)非常低级别和机器相关的,以及(b)不是普通C程序员应该拥有的那种东西在普通的编程任务中思考,(c)不能用C语言保证。

特别是,即使使用传统的线性寻址内存模型对计算机进行编程,您的程序也可能无法访问地址10,因此这些指针(cp和{{1} })可能是没用的,如果你试图使用它们可能会产生异常。 (另外,当我们有一个像ip这样的指针指向超过1个字节时,它会指向它指向哪个字节。如果ip是10,它可能指向字节10和11一个16位的字节寻址机器,但是这两个字节中的哪一个是int的低阶半部分,哪个是高阶的?这取决于它是“大端”还是“小端”机器。)

然后我们来指向空指针。当您使用常量“0”作为指针值时,情况会有所不同。如果你说

ip
严格来说,你不是说“让void *p = (void *)0; 指向p”。相反,你说“make 0是一个空指针”。但事实证明这与演员表无关,这是因为语言中的特殊情况:在指针上下文中,常量0表示空指针常量

空指针是一个特殊的指针值,它被定义为无处指向。它可能在内部表示为指向地址0的指针,或者它可能以其他方式表示。 (如果它实际上表示为指向地址0的指针,那么编译器会小心地安排在地址0处从来没有任何实际数据,因此即使它指向地址0,指针“仍然无法指向”仍然是正确的这有点令人困惑,抱歉。)

虽然指向p之类的原始地址的指针是低级别且危险且依赖于机器,但是空指针定义良好且完全正常。例如,当你调用10而它无法提供你要求的内存时,它会返回一个空指针来告诉你。当你测试malloc的返回值以查看它是成功还是失败时,你只需检查它是否给你一个空指针,并且没有任何低级别或不可移植或不鼓励这样做。< / p>

有关这一切的更多信息,请参阅http://c-faq.com/null/index.html

答案 1 :(得分:-1)

指针是字节的简短排列。通过强制转换,C允许假装这些字节表示整数。

Type* p = ...;
intptr_t i = (intptr_t)p;

当您需要将指针传递给期望整数的接口时,这偶尔(但很少)很有用。要恢复指针,只需反转强制转换。

Type* recovered_p = (Type*)i;

这不会分配任何内存。如果recovered_p包含的字节(如果被视为i)引用先前分配的Type*值,则只能推导Type。这意味着以下内容不会产生可用的指针:

int *p = (int*)10;

使用整数存储指针的示例。

typedef void (*Visitor)(intptr_t, ListNode*);

void List_visit(List* list, Visitor visitor, intptr_t arg) {
   for (ListNode* node = list->head; node; node=node->next) {
      visitor(arg, node);
   }
}

void printer(intptr_t arg, ListNode* node) {
   State* state = (intptr_t)arg;
   printf("%*s%s\n", ( state->count++ )*2, "", node->value);
}

int main(void) {
   List* list = ...;
   State* state = ...;
   List_visit(list, printer, (intptr_t)state);
   List_free(list);
   State_free(state);
   return 0;
}