char变量如何接受Pointer(NULL)作为其值?

时间:2013-04-11 16:51:34

标签: 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;
}

注意: GCC编译器(32位Linux平台)。

5 个答案:

答案 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替换为c89c99以强制执行标准的更高版本中的规则。 (编辑:我从评论中看到,您正在使用隐藏警告的编译器的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转换。