我已经看到NULL等价于(void*)0
。但我不明白为什么零需要被void*
括起来。当我们做这样的事情时,真正发生的事情
int *p = (int*)10;
(int*)
是否在上述语句中将整数10的地址空间(占用4个字节)扩展为8个字节?
答案 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
,我们又不会改变任何东西,我们只是重新解释一种不同的指针。
特别是,即使使用传统的线性寻址内存模型对计算机进行编程,您的程序也可能无法访问地址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;
}