只允许在C ++中定义行为?

时间:2011-04-06 18:49:02

标签: c++ visual-c++ gcc g++

是否可以在gcc / g ++或ms c ++中设置仅允许定义行为的标志?所以类似下面的内容会给我一个警告或最好是错误

func(a++, a, ++a)

5 个答案:

答案 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++);
}

如果ab具有相同的参赛作品,则会出现未定义的行为。通常,编译器无法知道将哪些参数传递给函数,因此无法可靠地捕获此未定义行为的情况。因此,它无法捕获所有未定义的行为。

编译器警告用于识别未定义行为的某些实例,但绝不会全部。

理论上,您可以编写一个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添加到上面的行,任何错误都会出错。主要是强制执行标准行为的stdpedantic选项,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而感谢

。所以在某种程度上,它已经实施了。但显然我们不能指望编译器能够识别所有未定义的行为。