是否可以在gcc / g ++或ms c ++中设置仅允许定义行为的标志?所以类似下面的内容会给我一个警告或最好是错误
func(a++, a, ++a)
答案 0 :(得分:8)
标准中明确指定了未定义和未指定的行为,因为它可能会对实现造成不应有的负担,以诊断其所有示例(或者无法确定)。
预计程序员会注意避免那些未定义的区域。
对于你陈述的例子,对于程序员来说,首先不要编写代码应该是相当明显的。
话虽如此,g++ -Wall
将捕获一些错误的代码,例如在非void函数中缺少返回以给出一个示例。
编辑:@sehe还指出-Wsequence-point
将捕获这个精确的代码构造,尽管每个参数的评估之间应该有一个序列点(但是未指定参数的评估顺序)。
答案 1 :(得分:7)
GNU C ++有以下内容
-Wsequence-point
Warn about code that may have undefined semantics because of violations of sequence point rules in the C and C++ standards.
这将正确标记您显示的调用
-Wstrict-overflow
-Wstrict-overflow
-fstrict-aliasing
-fstrict-overflow
HTH
答案 2 :(得分:3)
没有。例如,请考虑以下事项:
int badfunc(int &a, int &b) {
return func(a++, b++);
}
如果a
和b
具有相同的参赛作品,则会出现未定义的行为。通常,编译器无法知道将哪些参数传递给函数,因此无法可靠地捕获此未定义行为的情况。因此,它无法捕获所有未定义的行为。
编译器警告用于识别未定义行为的某些实例,但绝不会全部。
理论上,您可以编写一个C ++实现,该实现在运行时执行大量检查,以确保始终识别未定义的行为并以该实现定义的方式处理。它仍然不会在编译时告诉你(参见:停止问题),并且在实践中你可能会更好地使用C#,它旨在使必要的运行时检查合理有效...
即使你构建了那个神奇的检查C ++实现,它仍然可能不会告诉你你真正想知道的是什么,这是你的代码是否正确。有时(挂在你的座位上),无论行为是否未定义,都是实现定义的。举一个简单的例子,如果tolower((char)-1);
类型是无符号的,char
已定义行为[*],但如果char
类型已签名,则定义为未定义的行为。
因此,除非您的魔法检查实现与您希望代码运行的“真实”实现做出所有相同的实现选择,否则它不会告诉您代码是否已为所做的实现选择集定义了行为在“真实”实现中,只是它是否为魔法检查实现中的实现选择定义了行为。
要知道您的代码是正确且可移植的,您需要知道(对于初学者)它不会为任何实现选择集产生未定义的行为。就此而言,任何输入,而不仅仅是测试中使用的输入。您可能认为与没有未定义行为的语言相比,这是C ++的一大缺陷。当然它有时很不方便,并影响你如何进行沙盒程序的安全性。但实际上,为了让您认为代码正确,您不仅需要它来定义行为,您需要行为来匹配规范文档。这是一个很多更大的问题,在实践中,编写Java或Python中的错误并不比在C ++中编写错误要困难得多。我已经在这三个中写了无数错误,并且知道在Java或Python中行为已经定义但错误并没有帮助我这么多。
[*]嗯,结果仍然是实现定义的,它取决于执行字符集,但实现必须返回正确的结果。如果char
已签名,则允许其崩溃。
答案 3 :(得分:2)
这让我笑了。对此感到抱歉,并不意味着任何冒犯;这是一个很好的问题。
这个星球上没有编译器只允许100%定义的行为。事情的不确定性使它如此艰难。标准中涉及很多案例,但它们通常过于模糊,无法在编译器中有效实施。
我知道Clang开发人员对添加该功能感兴趣,但据我所知,他们还没有开始。
现在和远近的唯一可以做的就是提高编译器的警告级别和严格性。可悲的是,即使在最近的版本中,MSVC在这方面也是一种痛苦。在警告级别4及以上时,它会发出一些与代码正确性无关的愚蠢警告,而且你经常需要通过箍来让它们消失。
根据我的个人经历,海湾合作委员会在这方面做得更好。我个人使用这些选项,确保最严格的检查(我目前知道)-std=c++0x -pedantic -Wextra -Weffc++ -Wmissing-include-dirs -Wstrict-aliasing
我当然要确保零警告,如果你想强制执行,只需将-Werror
添加到上面的行,任何错误都会出错。主要是强制执行标准行为的std
和pedantic
选项,Wextra
会捕获一些偶然的半错误。
当然,如果可能的话,用不同的编译器编译你的代码(并确保他们通过在这里询问,人们知道标准所说/意味着什么来正确诊断问题。)
答案 4 :(得分:1)
虽然我同意马克的回答,但我只是觉得我应该让你知道......
#include <stdio.h>
int func(int a, int b, int c)
{
return a + b + c;
}
int main()
{
int a=0;
printf("%d\n", func(a++, a, ++a)); /* line 11 */
return 0;
}
使用gcc -Wall
编译上面的代码时,我收到以下警告:
test.c:11: warning: operation on ‘a’ may be undefined
test.c:11: warning: operation on ‘a’ may be undefined
我认为,因为a++
和++a
而感谢。所以在某种程度上,它已经实施了。但显然我们不能指望编译器能够识别所有未定义的行为。