Tim*_*Tim 5 c posix pointers null-pointer
来自Linux编程接口
Run Code Online (Sandbox Code Playgroud)execl(prog, arg, (char *) 0); execl(prog, arg, (char *) NULL);铸造
NULL在上述上次通话的方式,一般要求,甚至 在其中实现NULL被定义为(void *) 0.这是因为,虽然C标准要求不同类型的空指针在相等性比较时应该测试为真,但它们不要求不同类型的指针具有相同的内部表示(尽管在大多数实现中它们都这样).
并且, 在可变参数函数中,编译器无法强制(void *) 0转换为适当类型的空指针.在C类标准有一个例外的规则,不同类型的指针不必具有相同的表示:指针的类型
char *,并void *须具有相同的内部表示.这意味着在示例的情况下传递(void *) 0代替(char *) 0不会成为问题execl(),但是,在一般情况下,需要强制转换.
" NULL 通常需要以上述最后一次电话的方式进行投射 "
C标准是否要求空指针表示为(char*) 0?
"在变量函数中,例如execl(),编译器无法强制(void *) 0转换为适当类型的空指针."
是(void *) 0不是一个类型的空指针?
如果是的话,为什么不能编译投(void *) 0中execl(prog, arg, (void*) 0),以"适当的类型的空指针"?
"类型的指针char *和void *要求具有相同的内部表示.这意味着在示例情况下传递(void *) 0而不是(char *) 0问题execl()".
编译器可以投(void *) 0在execl(prog, arg, (void*) 0)到现在的"适当类型的空指针"?
为什么它与我的观点2中的引用相矛盾?
如果我替换(void *) 0在execl(prog, arg, (void*) 0)用0强制转换为任何类型的指针,例如(int *) 0,可以在编译器投(int *) 0中execl(prog, arg, (int*) 0),以"适当的类型的空指针"?谢谢.
对于非变量函数调用,例如in sigaction(SIGINT, &sa, (int*) 0),编译器是否可以转换(int *) 0 为"适当类型的空指针"?
谢谢.
首先,编译器在任何情况下都不会"强制转换".强制转换是源代码中的语法构造,它请求转换.
我将假设当你谈到"编译器转换"时,你的意思是谈论隐式转换,这是一种类型的值可以转换为另一种类型的值而没有转换运算符的过程.
标准准确地指出了可以应用隐式转换的上下文; 必须始终有目标类型.例如,在代码中int x = Y;,表达式Y可以是某种类型,它不是a int,但是具有对int定义的隐式转换.
...除了默认参数提升之外,没有对与原型部分对应的函数参数应用隐式转换.对于指针值,默认参数提升会保持不变.
您的问题的一个共同点是,编译器应该以某种方式假装execl行为就像为最后一个参数存在原型一样.但实际上没有,并且编译器对特定函数没有任何魔术行为.你传递的是你得到的.
该标准指定表达式的值(char *)0是空指针.它没有说明空指针的表示,并且可能有多个不同的表示都是空指针.
所述execl功能规范指出参数列表应该被终止由(char *)0它的类型的值char *.类型void *的值不是类型的值,char *并且在此上下文中没有隐式转换,如上所述.
仍然没有隐含的转换; 你引用的文字说你可以在这个特定情况下使用错误的类型参数(没有原型参数; char *预期但void *提供,反之亦然).
这将是未定义的行为,您在第3点引用的文本不适用于int *.
该sigaction功能有一个原型; 有问题的参数是struct sigaction *oldact.当您尝试使用不同类型的值初始化原型参数(或任何变量)时,将尝试隐式转换为参数类型.存在从任何空指针值到不同类型的空指针值的隐式转换.该规则在C11 6.3.2.3/4中.所以代码没问题.
从 C99 开始,reads的规范va_arg部分
如果 [
va_arg作为参数传递的类型] 与实际下一个参数的类型不兼容(根据默认参数提升),则行为未定义,以下情况除外:
- 一种类型是有符号整数类型,另一种类型是对应的无符号整数类型,值在两种类型中都可以表示;
- 一种类型是指向 void 的指针,另一种是指向字符类型的指针。
第二个要点意味着,对于任何va_arg用于访问其参数的可变参数函数,形式的调用
variadic_function("a", "b", "c", (void *)0);
Run Code Online (Sandbox Code Playgroud)
将在任何时候有效
variadic_function("a", "b", "c", (char *)0);
Run Code Online (Sandbox Code Playgroud)
本来可以。
不幸的是,有一个问题:我找不到对可变参数标准库函数1 的任何要求[行为就像它们] 通过对va_arg. 你可能在想,他们会怎么做呢?在实践中,它是va_arg手写的汇编语言,也许委员会不想要求手写的汇编语言完全等效,但我不会担心。
所以你引用的这本书在技术上是不正确的。不过,我还是会写
execl(prog, arg, (char *) NULL);
Run Code Online (Sandbox Code Playgroud)
如果我打算首先使用 NULL(我通常更喜欢0用作空指针常量),因为您不应该编写依赖于 NULL 扩展到 的代码((void *)0),并且
execl(prog, arg, 0);
Run Code Online (Sandbox Code Playgroud)
毫无疑问是不正确的。例如,当作为变量参数列表的一部分传递时,execl不会从0任何int32 位、char *64 位和int数量未符号或零扩展到 64 位的ABI 上接收空指针。
1 execl不是C标准的一部分,但它是 POSIX 标准的一部分,任何execl首先提供的系统都可能至少符合 POSIX 的一个子集。可以假设 C 标准的所有条款 7.1.4也适用于 POSIX 指定的函数。