未定义/未指定/实现定义的行为警告?
当编译器注意到具有未定义/未指定/实现定义的行为的语句时,它不能发出警告(如果抛出错误则更好)吗?
可能是将一个语句标记为错误,标准应该这么说,但它至少可以警告编码员。实施这样的选择是否存在任何技术困难?或者这根本就是不可能的?
我得到这个问题的原因是,在像 a[i] = ++i;
这样的语句中,它不会知道代码正在尝试引用变量并在同一语句中修改它吗?到达序列点。
Can't a compiler warn (even better if it throws errors) when it notices a statement with undefined/unspecified/implementation-defined behaviour?
Probably to flag a statement as error, the standard should say so, but it can warn the coder at least. Is there any technical difficulties in implementing such an option? Or is it merely impossible?
Reason I got this question is, in statements like a[i] = ++i;
won't it be knowing that the code is trying to reference a variable and modifying it in the same statement, before a sequence point is reached.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这一切都归结为
实施质量:警告越准确、越有用,就越好。编译器总是为每个程序打印:“这个程序可能会或可能不会调用未定义的行为”,然后对其进行编译,这是非常无用的,但符合标准。值得庆幸的是,没有人编写这样的编译器:-)。
易于确定:编译器可能无法轻松确定未定义的行为、未指定的行为或实现定义的行为。假设您有一个 5 层深的调用堆栈,其中一个 const char * 参数从顶层传递到链中的最后一个函数,最后一个函数调用 printf () 并将
const char *
作为第一个参数。您是否希望编译器检查 const char * 以确保其正确? (假设第一个函数使用该值的文字字符串。)当从文件中读取 const char * 时怎么样,但您知道该文件将始终包含值的有效格式说明符正在打印?成功率:编译器可能能够检测到许多可能未定义、未指定等的构造;但“成功率”非常低。在这种情况下,用户不希望看到大量“可能未定义”消息 - 太多虚假警告消息可能会隐藏真正的警告消息,或者提示用户在“低警告”设置下进行编译。这很糟糕。
对于您的特定示例,
gcc
给出有关“可能未定义”的警告。它甚至会警告printf()
格式不匹配。但是,如果您希望编译器能够对所有未定义/未指定的情况发出诊断,则不清楚这是否应该/可以工作。
假设您有以下内容:
编译器是否应该警告您有关
*a = ++*b;
行?正如 gf 在评论中所说,编译器无法跨翻译单元检查未定义的行为。经典示例是在一个文件中将变量声明为指针,然后在另一个文件中将其定义为数组,请参阅 comp.lang.c 常见问题解答 6.1。
It all boils down to
Quality of Implementation: the more accurate and useful the warnings are, the better it is. A compiler that always printed: "This program may or may not invoke undefined behavior" for every program, and then compiled it, is pretty useless, but is standards-compliant. Thankfully, no one writes compilers such as these :-).
Ease of determination: a compiler may not be easily able to determine undefined behavior, unspecified behavior, or implementation-defined behavior. Let's say you have a call stack that's 5 levels deep, with a
const char *
argument being passed from the top-level, to the last function in the chain, and the last function callsprintf()
with thatconst char *
as the first argument. Do you want the compiler to check thatconst char *
to make sure it is correct? (Assuming that the first function uses a literal string for that value.) How about when theconst char *
is read from a file, but you know that the file will always contain valid format specifier for the values being printed?Success rate: A compiler may be able to detect many constructs that may or may not be undefined, unspecified, etc.; but with a very low "success rate". In that case, the user doesn't want to see a lot of "may be undefined" messages—too many spurious warning messages may hide real warning messages, or prompt a user to compile at "low-warning" setting. That is bad.
For your particular example,
gcc
gives a warning about "may be undefined". It even warns forprintf()
format mismatch.But if your hope is for a compiler that issues a diagnostic for all undefined/unspecified cases, it is not clear if that should/can work.
Let's say you have the following:
Should the compiler warn you about
*a = ++*b;
line?As gf says in the comments, a compiler cannot check across translation units for undefined behavior. Classic example is declaring a variable as a pointer in one file, and defining it as an array in another, see comp.lang.c FAQ 6.1.
gcc 在这种情况下确实发出警告(至少使用
-Wall
):给出:
编辑:
快速阅读 手册页 显示,如果您出于某种原因不需要
-Wall
,则-Wsequence-point
会执行此操作。gcc does warn in that situation (at least with
-Wall
):Gives:
Edit:
A quick read of the man page shows that
-Wsequence-point
will do it, if you don't want-Wall
for some reason.不同的编译器捕获不同的条件;大多数编译器都有警告级别选项,GCC 特别有很多,但 -Wall -Werror 将打开大多数有用的选项,并强制它们出错。在 VC++ 中使用 \W4 \WX 进行类似的保护。
在 GCC 中,您可以使用 -ansi -pedantic,但 pedantic 就是它所说的,并且会引发许多不相关的问题,并使使用大量第三方代码变得困难。
无论哪种方式,因为编译器捕获不同的错误,或者为同一错误生成不同的消息,因此使用多个编译器很有用,不一定用于部署,而是作为穷人的静态分析。 C 代码的另一种方法是尝试将其编译为 C++; C++ 更强的类型检查通常会产生更好的 C 代码;但请确保,如果您希望 C 编译起作用,请不要专门使用 C++ 编译;您可能会介绍 C++ 的特定功能。同样,这不需要部署为 C++,而只是用作附加检查。
最后,编译器通常是在性能和错误检查之间取得平衡的。彻底检查需要花费很多开发人员无法接受的时间。因此存在静态分析器,对于 C 来说,有传统的 lint 和开源夹板。 C++ 的静态分析更加复杂,而且工具通常非常昂贵。我用过的最好的之一是来自Programming Research 的QAC++。我不知道有任何有名气的免费或开源 C++ 分析器。
Different compilers trap different conditions; most compilers have warning level options, GCC specifically has many, but -Wall -Werror will switch on most of the useful ones, and coerce them to errors. Use \W4 \WX for similar protection in VC++.
In GCC You could use -ansi -pedantic, but pedantic is what it says, and will throw up many irrelevant issues and make it hard to use much third party code.
Either way, because compilers catch different errors, or produce different messages for the same error, it is therefore useful to use multiple compilers, not necessarily for deployment, but as a poor-man's static analysis. Another approach for C code is to attempt to compile it as C++; the stronger type checking of C++ generally results in better C code; but be sure that if you want C compilation to work, don't use the C++ compilation exclusively; you are likely to introduce C++ specific features. Again this need not be deployed as C++, but just used as an additional check.
Finally, compilers are generally built with a balance of performance and error checking; to check exhaustively would take time that many developers would not accept. For this reason static analysers exist, for C there is the traditional lint, and the open-source splint. C++ is more complex to statically analyse, and tools are often very expensive. One of the best I have used is QAC++ from Programming Research. I am not aware of any free or open source C++ analysers of any repute.
相反,编译器不需要对未定义的行为进行任何类型的诊断:
强调我的。虽然我同意这可能很好,但编译器在尝试符合标准方面有足够的问题,更不用说教程序员如何编程了。
Contrarily, compilers are not required to make any sort of diagnosis for undefined behavior:
Emphasis mine. While I agree it may be nice, the compiler's have enough problem trying to be standards compliant, let alone teach the programmer how to program.
当你做一些不符合语言规范的事情时,GCC 会尽可能多地发出警告,同时在语法上仍然正确,但超出某一点时,必须得到足够的通知。
您可以使用
-Wall
标志调用 GCC 以查看更多内容。GCC warns as much as it can when you do something out of the norms of the language while still being syntactically correct, but beyond the certain point one must be informed enough.
You can call GCC with the
-Wall
flag to see more of that.如果您的编译器不会发出警告,您可以尝试 Linter。
Splint 是免费的,但仅检查 C http://www.splint.org/
Gimpel Lint 支持 C++,但售价 389 美元 - 也许可以说服您的公司购买一本? http://www.gimpel.com/
If your compiler won't warn of this, you can try a Linter.
Splint is free, but only checks C http://www.splint.org/
Gimpel Lint supports C++ but costs US $389 - maybe your company c an be persuaded to buy a copy? http://www.gimpel.com/