我知道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;
}
注意: GCC编译器(32位Linux平台)。
答案 0 :(得分:9)
NULL
宏需要扩展为“实现定义的空指针常量”。
空指针常量定义为“值为0的整数常量表达式,或者此类表达式转换为类型void *
”。与直觉相反,这个定义确实不要求将NULL
扩展为指针类型的表达式。一个常见的实现是:
#define NULL 0
当在需要指针的上下文中使用时,空指针常量可以隐式转换为指针值;结果是空指针。它也可以使用强制转换显式转换,例如(int*)NULL
。
但是,并不要求限定为空指针常量的表达式只能在这样的上下文中使用。这意味着 if 实现选择如上定义NULL
,那么:
char c = NULL; // legal but ugly
是合法的,并将c
初始化为null 字符。
这样的初始化是不可移植的(因为NULL
也可能扩展到((void*)0)
并且误导,所以应该避免,但是编译器可能会在没有警告的情况下通过它; {{1通过编译器的预处理阶段扩展到NULL
,后面的阶段将其视为0
,这是合法且无害的 - 尽管我个人更喜欢char c = 0;
。 / p>
我刚刚在我自己的32位Ubuntu系统上尝试了你的例子,gcc 4.7。如果未指定选项,编译器会警告char c = '\0';
和p[2]=NULL;
:
p[1]=(void *)0;
第二个警告是任何C编译器的预期;第一个表示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]
实际上定义为NULL
(通过((void*)0)
运行代码确认了这一点。)
编译器没有简单地“接受”这些作业;它警告过你。 C语言标准仅需要对任何违反语言规则的行为进行“诊断”,甚至是语法错误;该诊断可能在法律上是一个非致命的警告信息。您可以使用gcc -E
更严格地使gcc行为;将-std=c89 -pedantic-errors
替换为c89
或c99
以强制执行标准的更高版本中的规则。 (编辑:我从评论中看到,您正在使用隐藏警告的编译器的Web界面;请参阅我对您的问题的评论以获得解决方法。警告很重要。)
如果您发布产生编译器警告的C代码,请 向我们显示警告并亲自关注它们。他们经常在你的计划中表明严重的问题,甚至是非法行为。
语言律师狡辩:它甚至不清楚:
c11
指定从char c = (void*)0;
到void*
的转化。我自己的观点是,由于它违反了约束,因此它没有定义的语义。大多数不拒绝它的编译器会将其视为char
到 - void*
转换,并且还有人认为这是必需的行为。但是,如果您只是注意编译器警告和/或不首先编写类似的代码,就可以避免这些问题。
(对于C ++,规则有点不同,但你要问的是C所以我不会深入研究。)
答案 1 :(得分:2)
因为在编译器中,NULL
在某些编译器中被替换为0而在其他编译器中被替换为((void*)0)
。
值0
本身是char
的有效值,但是转换为(void*)
,你在技术上将0转换为指针类型,因此编译器会发出警告。
请注意,如果编译器将NULL
替换为0(整数常量),它将被简单而无声地转换为char
。
答案 2 :(得分:2)
NULL
是一个宏,几乎平台就是以这种方式定义的
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
(来自我的Ubuntu的stddef.h
)
当你写
p[2]=NULL;
它是一样的
p[2]=(void *)0; //for c
p[2]=0; //for c++
它是一样的
p[2] = 0; // the 0 is casted to char 0 for C --> '\0'
答案 3 :(得分:2)
在您的平台上,指针通常是一个被视为内存地址的数值。由于char
类型是数字,因此空指针(内存地址0x00
)存储在p[1]
指针的32位值(在本例中为0x00000000
)被截断为8位char
长度:0x00
。
答案 4 :(得分:1)
尝试使用-Wall
选项对其进行编译,您会看到正在进行impilicit转换。