基于三元运算符 (?:) 的赋值避免了 C 中的类型检查

R.k*_*ana 0 c gcc conditional-operator void-pointers implicit-conversion

我无法理解为什么编译器在分配不兼容的指针时不发出警告(?:),但在直接分配时发出警告。

\n

在这种情况下编译器会发出警告:

\n
\n

test.c:在函数 \xe2\x80\x98main\xe2\x80\x99 中:test.c:8:4:警告:分配给\n\xe2\x80\x98uint32_t *\xe2\x80\x99 {aka \xe2 \x80\x98unsigned int *\xe2\x80\x99} 来自不兼容的指针类型\n\xe2\x80\x98uint32_t **\xe2\x80\x99 {aka \xe2\x80\x98unsigned int **\xe2\x80\x99 } [-Win兼容指针类型]\n8 | a = 数组;\n| ^

\n
\n
#include <stdint.h>\n#include <stdlib.h>\n\nint main(void)\n{\n    uint32_t *array[10], *a;\n    a = array;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

以下情况不会发出警告:

\n
#include <stdint.h>\n#include <stdlib.h>\n\nint main(void)\n{\n    int b = 8;\n    uint32_t *array[10], *a;\n\n    a = (b >= 8) ? array : malloc(8);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

环境:

\n
Gcc version 9.3.0\nUbuntu 20.04\ncompilation cmd: gcc test.c -o test.out\n
Run Code Online (Sandbox Code Playgroud)\n

Kev*_*vin 8

表达式的类型(b >= 8) ? array : malloc(8)void*(因为malloc(8)具有类型void*)。您可以通过做一些无意义的事情并让编译器告诉您来看到这一点:

((b >= 8) ? array : malloc(8)) * 5;
Run Code Online (Sandbox Code Playgroud)
<source>:10:36: error: invalid operands to binary * (have 'void *' and 'int')
   10 |     ((b >= 8) ? array : malloc(8)) * 5;
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
      |                       |
      |                       void *
Run Code Online (Sandbox Code Playgroud)

void*可以隐式转换为任何类型的指针,这就是为什么当您将该值分配给 时编译器不会抱怨a

  • 更准确地说:三元运算符的一个特定规则是允许第二个和第三个操作数之一是指向“void”的限定或非限定指针,而另一个可以具有任何对象指针类型,在在这种情况下,结果是一个适当限定的指向“void”的指针。这不是特别关于“malloc”,也不是关于第三个操作数*与第二个操作数。 (3认同)

Vla*_*cow 7

来自 C 标准(6.5.15 条件运算符)

  1. ...否则,一个操作数是指向 void 或 void 的限定版本的指针,在这种情况下,结果类型是指向 void 的适当限定版本的指针。

该函数malloc返回类型为 的指针void *。所以带有条件运算符的表达式的类型是void *。并且该类型的指针void *可以分配给任何其他对象类型的指针。

来自 C 标准(6.3.2.3 指针)

1 指向 void 的指针可以与指向任何对象类型的指针相互转换。指向任何对象类型的指针都可以转换为指向 void 的指针,然后再转换回来;结果应等于原始指针。

事实上你有

a = ( void * )(b >= 8 ? array : malloc(8) );
Run Code Online (Sandbox Code Playgroud)