未定义/未指定/实现定义的行为警告?

发布于 2024-08-22 10:29:50 字数 218 浏览 14 评论 0原文

当编译器注意到具有未定义/未指定/实现定义的行为的语句时,它不能发出警告(如果抛出错误则更好)吗?

可能是将一个语句标记为错误,标准应该这么说,但它至少可以警告编码员。实施这样的选择是否存在任何技术困难?或者这根本就是不可能的?

我得到这个问题的原因是,在像 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

み格子的夏天 2024-08-29 10:29:50

这一切都归结为

  • 实施质量:警告越准确、越有用,就越好。编译器总是为每个程序打印:“这个程序可能会或可能不会调用未定义的行为”,然后对其进行编译,这是非常无用的,但符合标准。值得庆幸的是,没有人编写这样的编译器:-)。

  • 易于确定:编译器可能无法轻松确定未定义的行为、未指定的行为或实现定义的行为。假设您有一个 5 层深的调用堆栈,其中一个 const char * 参数从顶层传递到链中的最后一个函数,最后一个函数调用 printf () 并将 const char * 作为第一个参数。您是否希望编译器检查 const char * 以确保其正确? (假设第一个函数使用该值的文字字符串。)当从文件中读取 const char * 时怎么样,但您知道该文件将始终包含值的有效格式说明符正在打印?

  • 成功率:编译器可能能够检测到许多可能未定义、未指定等的构造;但“成功率”非常低。在这种情况下,用户不希望看到大量“可能未定义”消息 - 太多虚假警告消息可能会隐藏真正的警告消息,或者提示用户在“低警告”设置下进行编译。这很糟糕。

对于您的特定示例,gcc 给出有关“可能未定义”的警告。它甚至会警告 printf() 格式不匹配。

但是,如果您希望编译器能够对所有未定义/未指定的情况发出诊断,则不清楚这是否应该/可以工作。

假设您有以下内容:

#include <stdio.h>
void add_to(int *a, int *b)
{
    *a = ++*b;
}

int main(void)
{
    int i = 42;
    add_to(&i, &i); /* bad */
    printf("%d\n", i);
    return 0;
}

编译器是否应该警告您有关 *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 calls printf() with that const char * as the first argument. Do you want the compiler to check that const char * to make sure it is correct? (Assuming that the first function uses a literal string for that value.) How about when the const 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 for printf() 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:

#include <stdio.h>
void add_to(int *a, int *b)
{
    *a = ++*b;
}

int main(void)
{
    int i = 42;
    add_to(&i, &i); /* bad */
    printf("%d\n", i);
    return 0;
}

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.

扛起拖把扫天下 2024-08-29 10:29:50

gcc 在这种情况下确实发出警告(至少使用 -Wall):

#include <stdio.h>

int main(int argc, char *argv[])
{
  int a[5];
  int i = 0;

  a[i] = ++i;

  printf("%d\n", a[0]);

  return 0;
}

给出:

$ make
gcc -Wall main.c -o app
main.c: In function ‘main’:
main.c:8: warning: operation on ‘i’ may be undefined

编辑:

快速阅读 手册页 显示,如果您出于某种原因不需要 -Wall,则 -Wsequence-point 会执行此操作。

gcc does warn in that situation (at least with -Wall):

#include <stdio.h>

int main(int argc, char *argv[])
{
  int a[5];
  int i = 0;

  a[i] = ++i;

  printf("%d\n", a[0]);

  return 0;
}

Gives:

$ make
gcc -Wall main.c -o app
main.c: In function ‘main’:
main.c:8: warning: operation on ‘i’ may be undefined

Edit:

A quick read of the man page shows that -Wsequence-point will do it, if you don't want -Wall for some reason.

乱了心跳 2024-08-29 10:29:50

不同的编译器捕获不同的条件;大多数编译器都有警告级别选项,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.

当爱已成负担 2024-08-29 10:29:50

相反,编译器不需要对未定义的行为进行任何类型的诊断:

§1.4.1:
可诊断规则集由本国际标准中的所有语法和语义规则组成,但包含“不需要诊断”的明确注释的规则或被描述为导致“未定义的行为”的规则除外。

强调我的。虽然我同意这可能很好,但编译器在尝试符合标准方面有足够的问题,更不用说教程序员如何编程了。

Contrarily, compilers are not required to make any sort of diagnosis for undefined behavior:

§1.4.1:
The set of diagnosable rules consists of all syntactic and semantic rules in this International Standard except for those rules containing an explicit notation that “no diagnostic is required” or which are described as resulting in “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.

输什么也不输骨气 2024-08-29 10:29:50

当你做一些不符合语言规范的事情时,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.

心在旅行 2024-08-29 10:29:50

如果您的编译器不会发出警告,您可以尝试 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/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文