编译器能否将 `(void *) 0` 中的 `execl(prog, arg, (void*) 0)` 转换为适当类型的空指针?

标签 c pointers posix null-pointer

来自 Linux 编程接口(interface)

execl(prog, arg, (char *) 0);
execl(prog, arg, (char *) NULL);

Casting NULL in the manner of the last call above is generally required, even on implementations where NULL is defined as (void *) 0.

This is because, although the C standards require that null pointers of different types should test true for comparisons on equality, they don’t require that pointers of different types have the same internal representation (although on most implementations they do).
And, in a variadic function, the compiler can’t cast (void *) 0 to a null pointer of the appropriate type.

The C standards make one exception to the rule that pointers of different types need not have the same representation: pointers of the types char * and void * are required to have the same internal representation. This means that passing (void *) 0 instead of (char *) 0 would not be a problem in the example case of execl(), but, in the general case, a cast is needed.

  1. “通常需要按照上面最后一次调用的方式转换NULL

    C 标准是否要求将空指针表示为与 (char*) 0 相同?

  2. “在诸如 execl() 的可变参数函数中,编译器无法将 (void *) 0 转换为适当类型的空指针”

    (void *) 0 不是一个类型的空指针吗?

    如果是,为什么编译器不能将 execl(prog, arg, (void*) 0) 中的 (void *) 0 转换为“空指针”合适的类型”?

  3. char *void * 类型的指针必须具有相同的内部表示。这意味着传递 (void *) 0 而不是 (char *) 0execl() 的例子中不会有问题。

    编译器现在可以将 execl(prog, arg, (void*) 0) 中的 (void *) 0 转换为“适当类型的空指针”吗?

    为什么它与我的第 2 点中的引用相矛盾?

  4. 如果我将 execl(prog, arg, (void*) 0) 中的 (void *) 0 替换为 0 到任何类型指针的转换,例如(int *) 0,编译器可以在execl(prog, arg, (int*) 0)中转换(int *) 0 > 到“适当类型的空指针”? 谢谢。

  5. 对于非可变函数调用,例如在 sigaction(SIGINT, &sa, (int*) 0) 中,编译器是否可以转换 (int *) 0 到“适当类型的空指针”?

谢谢。

最佳答案

首先,编译器在任何情况下都不会“转换”。强制转换是源代码中请求转换的语法结构。

我假设当您谈论“编译器转换”时,您指的是隐式转换,即一种类型的值可以转换为另一种类型的值的过程,没有施法者。

该标准明确规定了可以应用隐式转换的上下文;必须始终有一个目标类型。例如在代码 int x = Y; 中,表达式 Y 可以是某种不是 int 的类型,但隐式转换为int 定义。

没有隐式转换应用于对应于原型(prototype)的 ... 部分的函数参数,default argument promotions 除外.对于指针值,默认参数提升保持不变。

你的问题的一个共同点似乎是编译器应该以某种方式假装 execl 的行为就好像最后一个参数有一个原型(prototype)一样。但实际上并没有,编译器对特定的函数也没有任何神奇的行为。你传递的就是你得到的。


  1. 标准指定表达式(char *)0 的值为空指针。它没有提到空指针的表示,并且可能有多种不同的表示都是空指针。

  2. execl 函数规范指出参数列表应该以 (char *)0 结束,它是 char *< 类型的值void * 类型的值不是 char * 类型的值,如上所述,在此上下文中没有隐式转换。

  3. 仍然没有隐式转换;您引用的文字是说您可以在这种特定情况下使用错误的类型参数(没有原型(prototype)参数;并且 char * 预期但 void * 提供,反之亦然).

  4. 那将是未定义的行为,您在第 3 点中引用的文本不适用于 int *

  5. sigaction 函数有一个原型(prototype);有问题的参数是 struct sigaction *oldact。当您尝试使用不同类型的值初始化原型(prototype)参数(或任何变量)时,将尝试隐式转换为参数类型。存在从任何空指针值到不同类型的空指针值的隐式转换。此规则在 C11 6.3.2.3/4 中。这样代码就OK了。

关于编译器能否将 `(void *) 0` 中的 `execl(prog, arg, (void*) 0)` 转换为适当类型的空指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52195275/

相关文章:

php - 编译失败 : POSIX collating elements are not supported

c - 如何解释此 PMAP 输出?

c - 如何在可能的递归过程中设置缓冲区?

c - 在dev c++中运行简单的c程序时出错

c - 参数数量与原型(prototype)不匹配等

C for循环几乎正确

C 编程 - 指针出现问题,没有控制台输出

c - 右排列文本中的单词

C# 对象引用 : How can i do it?

ipc - 在 posix 的命名管道上将多个进程写入单个读取器是否会产生影响?