至少有三篇关于如何在C中禁止无效指针算术的帖子; gcc 4.8.2允许它,假设void是字节大小;以及如何打开额外的迂腐警告以触发错误。这是一个例子:
#include <stdio.h>
/* compile gcc -Wall -o try try.c */
int main() {
char *str="string";
void *vp= (void *) str;
++vp; /* arithmetic on void point. huh? */
printf("%s\n", (char*)vp);
return 0;
}
我的问题是考虑在无效代码的情况下C编译器应该做什么。当编译器没有对无效代码发出编译错误时,它不被视为错误吗?
这对于编译器来说似乎是奇怪的行为 - 无论如何 - 即使gcc没有发出编译错误,至少它可能会发出一个&#34;弃用的#34;使用默认编译器标志进行警告。而且,即使有
-Wall
,它甚至没有发出警告。咦?这让我感到惊讶,因为gcc看起来非常成熟,而C并不是一种新颖或复杂的语言。
答案 0 :(得分:12)
C标准尝试对void*
约束违规执行指针运算,这意味着任何符合要求的C编译器必须为包含此类的任何程序发出至少一条诊断消息尝试。警告可能是非致命错误;在这种情况下,编译器可以继续生成其行为由实现定义的代码。
gcc不会对void*
上的指针算法发出警告。这意味着默认情况下,gcc 不是符合C的编译器。
有人可能会认为这是一个错误,但在默认模式下,gcc不是标准C的编译器,而是GNU C.(Fortran编译器未能成为符合标准的C编译器也不是错误。)
精心选择的命令行选项可以强制gcc至少尝试符合要求。例如:
gcc -std=cXX -pedantic
其中XX
是90
,99
或11
之一,会导致gcc警告void*
上的指针算术。用-pedantic
替换-pedantic-errors
会导致它将此类算法视为致命错误。
答案 1 :(得分:2)
确定无效的标准C代码在特定编译器中可能是合法的,它被称为编译器扩展。
在这种情况下,来自https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html
在GNU C中,指向void的指针和指向函数的指针都支持加法和减法操作。这是通过将空白或函数的大小视为1来完成的。
如果您需要可移植代码,那么坚持使用标准C始终是个好主意,但如果您的代码仅在特定平台上运行,那么使用某些编译器扩展并没有坏处。
答案 2 :(得分:0)
C11标准n1570 S6.5.6 / 2:
另外,两个操作数都应具有算术类型,或者一个操作数应为a 指向完整对象类型的指针,另一个指针应具有整数类型。 (递增是 相当于添加1。)
C ++的语言类似。
它绝对不符合标准的行为。我认为GCC团队已经知道了。
答案是兼容的编译器应该发出诊断,然后生成它喜欢的代码(或不代码)。