Nee*_*raj 5 c pointers void-pointers
我明白char变量可以接受一个null字符(1个字节)即; \0作为它的值但是,我不明白我的应用程序中的char变量如何接受指针(4个字节)作为其值并仍然正常工作?
#include<stdio.h>
int main()
{
char p[10]="Its C";
printf("%s\n",p);
p[3]='\0'; // assigning null character
printf("%s\n",p);
p[2]=NULL; // assigning null pointer to a char variable
printf("%s\n",p);
p[1]=(void *)0; // assigning null pointer to a char variable
printf("%s\n",p);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
注意: GCC编译器(32位Linux平台).
该NULL宏需要扩展为"实现定义的空指针常量".
甲空指针常数被定义为"一个整数常量表达式用值0,或者这样转换为键入一个表达式void *".违反直觉地,此定义并没有要求的膨胀NULL是指针类型的表达式.一个常见的实现是:
#define NULL 0
Run Code Online (Sandbox Code Playgroud)
当在需要指针的上下文中使用时,空指针常量可以隐式地转换为指针值; 结果是一个空指针.它也可以使用强制转换显式转换,例如(int*)NULL.
但是,并不要求限定为空指针常量的表达式只能在这样的上下文中使用.这意味着如果实现选择NULL如上定义,那么:
char c = NULL; // legal but ugly
Run Code Online (Sandbox Code Playgroud)
是合法的并初始化c为null 字符.
这样的初始化是不可移植的(因为它NULL也可以扩展到((void*)0)并且误导,所以应该避免,但编译器很可能在没有警告的情况下通过它; 通过编译器的预处理阶段NULL扩展到0,后来阶段看到它因为char c = 0;,这是合法和无害的 - 虽然我个人更喜欢char c = '\0';.
我刚刚在我自己的32位Ubuntu系统上尝试了你的例子,gcc 4.7.如果不指定任何选项,则编译器警告都p[2]=NULL;和p[1]=(void *)0;:
c.c:8:9: warning: assignment makes integer from pointer without a cast [enabled by default]
c.c:10:9: warning: assignment makes integer from pointer without a cast [enabled by default]
Run Code Online (Sandbox Code Playgroud)
任何C编译器都可以预期第二个警告; 第一个表示NULL实际定义为((void*)0)(通过gcc -E确认运行代码).
编译器并不是简单地"接受"这些任务; 它警告过你.C语言标准仅需要对任何违反语言规则的行为进行"诊断",甚至是语法错误; 该诊断可能在法律上是一个非致命的警告信息.你可以使gcc表现得更加严格-std=c89 -pedantic-errors; 更换c89用c99或c11强制从更高版本的标准规则.(编辑:我从评论中看到你正在使用隐藏警告的编译器的Web界面;请参阅我对你的问题的评论以获得解决方法.警告很重要.)
如果您发布产生编译器警告的C代码,请 告诉我们警告并自己密切关注它们.他们经常在您的计划中表明存在严重问题,甚至是非法行为.
语言律师狡辩:它甚至不清楚:
char c = (void*)0;
Run Code Online (Sandbox Code Playgroud)
指定从一个转换void*到char.我自己的观点是,由于它违反了约束,因此它没有定义的语义.不拒绝它就会把它当作好像它是一个大多数编译器void*-到- char转换,它也有人认为这是必要的行为.但是,如果您只是注意编译器警告和/或首先不编写类似的代码,您可以避免这些问题.
(对于C++,规则有点不同,但你要问的是C,所以我不会进入.)