在 VC9 中编译时不会出现警告级别 4 的警告。为什么人们不认为这是一种编译器缺陷呢?

发布于 2024-08-03 19:11:06 字数 902 浏览 6 评论 0原文

我看到一些发布的代码有超出范围的错误,这让我感到好奇。我希望编译器会为此代码生成警告(至少在最高级别),

#pragma warning(push,4)
int main(){
    int x[2];
    x[2]=0;     
    return 0;
}
#pragma warning(pop)

但事实并非如此。

EDG 编译器很好地表示:

"sourceFile.cpp", line 3: warning:
          subscript out of range
          x[2]=0;
          ^

实际上 EDG 说得更多(所有这些都是预期的),

"sourceFile.cpp", line 1: warning: 
          unrecognized #pragma
  #pragma warning(push,4)
          ^

"sourceFile.cpp", line 4: warning: 
          subscript out of range
      x[2]=0;     
      ^

"sourceFile.cpp", line 3: warning: 
          variable "x" was set but never used
      int x[2];
          ^

"sourceFile.cpp", line 7: warning: 
          unrecognized #pragma
  #pragma warning(pop)

但这不是我的问题。

我认为这个失败警告了 VC9 中的严重遗漏错误(自从使用自动变量以来更是如此!!!)。谁能给我一个改变主意的严肃理由?

I saw some posted code with an out of range error on SO that made me wonder. I would expect a compiler to generate a warning (at the highest level at least) for this code

#pragma warning(push,4)
int main(){
    int x[2];
    x[2]=0;     
    return 0;
}
#pragma warning(pop)

but it does not.

The EDG compiler nicely says:

"sourceFile.cpp", line 3: warning:
          subscript out of range
          x[2]=0;
          ^

Actually EDG says bit more more(all of which are expected)

"sourceFile.cpp", line 1: warning: 
          unrecognized #pragma
  #pragma warning(push,4)
          ^

"sourceFile.cpp", line 4: warning: 
          subscript out of range
      x[2]=0;     
      ^

"sourceFile.cpp", line 3: warning: 
          variable "x" was set but never used
      int x[2];
          ^

"sourceFile.cpp", line 7: warning: 
          unrecognized #pragma
  #pragma warning(pop)

but that's not my question.

I consider this failure to warn a SERIOUS error of omission in VC9,(even more so since an auto variable!!!!). Can anyone give me a serious reason to change my mind?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(7

撕心裂肺的伤痛 2024-08-10 19:11:06

许多编译器都有选项来错误地处理此类事情。

但对于 C 编译器来说,默认放弃这一点是非常传统的,甚至是正确的。造成这种情况的原因有很多。

  1. 请记住,x[i]i[x] 在 C 中是相同的。您甚至可以执行 "string"[2] 或者您可以执行 2["string"] 并获得相同的结果。尝试一下。这是因为 x[i] 被定义为 *(x + i) 并且一旦 C 只是进行指针算术,然后取消引用它不在其中的表达式的结果编译器的域来决定它是否能够工作。

  2. 鉴于指针算术是合法的,许多当时相当不错的设计模式实际上依赖于技术下标违规

    结构体{
        ...一堆东西...
        整数点[1]; // 并非如此 [1]
    };
    ...
    struct s *p = malloc(sizeof (struct s) + someNumber * sizeof(int));
    
    
    

    今天到处都在运行这样的代码...    更新:嘿,这是一个实际的stackoverflow 上的 struct hack 示例

Many compilers have options to error out this kind of thing.

But it's quite traditional and even proper for C compilers to let this go by default. There are multiple reasons for this.

  1. Remember that x[i] and i[x] are the same thing in C. You can even do "string"[2] OR you can do 2["string"] and get the same result. Try it. And this is because x[i] is defined as *(x + i) and once C is just doing pointer arithmetic and then derefing the result of the expression it's not in the compiler's domain to decide that it's going to work or not.

  2. Given that pointer arithmetic is legal, lots of fairly-decent-for-their-day design patterns actually depend on technical subscript violations

    struct s {
        ...bunch of stuff...
        int points[1]; // not really [1]
    };
    ...
    struct s *p = malloc(sizeof (struct s) + someNumber * sizeof(int));
    

    There is code like this running today all over the place...    Update: heh, here is an actual example of the struct hack on stackoverflow.

翻了热茶 2024-08-10 19:11:06

编译器不需要对未定义的行为发出警告(即使是像这样的“严重”行为)。许多编译器倾向于检查不同的行为集。我认为如果您有 VSTS,则可以启用一些额外的安全检查,因此这可能会被捕获。此外,编译器可以插入运行时检查来捕获此内存覆盖(可能用于调试版本),因此您应该确保启用了这些检查。

The compiler is not required to issue warnings for undefined behaviour (even "serious" ones like this). Many compilers have different sets of behaviour that they tend to check for. I think that if you have VSTS, there is some additional security checks that can be enabled so this might be caught by that. Additionally, the compiler can insert runtime checks that will catch this memory overwrite (probably for debug builds), so you should make sure that you have those enabled.

情魔剑神 2024-08-10 19:11:06

虽然给出的示例非常简单,但要在编译期间做好静态分析通常需要大量代码并减慢编译速度(简单的实现意味着再次通过 AST)。

在一种经常因编译缓慢而受到谴责的语言中。

让你变得愚蠢是 C++ 的重要组成部分。试图让你摆脱困境的编译器很好,但那是肉汁。

FWIW:g++ -Wall 也无法发出警告。

While the example given is pretty simple, to do a good job of static analysis during compilation in general would take considerable code and slow down the compilation (a naive implementation means another pass over the AST).

In a language already often berated for slow compiles.

Letting you be stupid is part and parcel of c++. Compilers that try to save you from yourself are nice, but that is gravy.

FWIW: g++ -Wall also fails to warn.

感受沵的脚步 2024-08-10 19:11:06

对源执行静态代码分析时会发出此警告。不过,静态代码分析不是编译器规范的一部分(至少据我所知),并且是由单独的工具完成的。

以下是C/C++ 代码分析的概述。以及该工具涵盖的警告列表

This warning is issued when a static code analysis is performed on the sources. Static code analysis is not a part of the compiler specification, though (at least as far as I know), and is done by a separate tool.

Here's an overview of the C/C++ code analysis. And the list of warnings covered by the tool.

喵星人汪星人 2024-08-10 19:11:06

它没有对此发出警告的原因是它很少有用。查看您的代码:

int main(){
    int x[2];
    x[2]=0;     
    return 0;
}

我们看到在这种情况下编译器能够发出警告,但这只是因为:

  • 数组尚未衰减为指针 - 换句话说,大小信息是仍然可用,并且
  • 您正在使用编译时常量表达式来索引数组。

在大多数现实世界的代码中,这两个条件都不成立。数组几乎总是一个指针,在这种情况下编译器根本没有大小信息。同样,您经常使用运行时确定的值来索引数组。再说一遍,如果你这样做,编译器将无法确定你是否会超出范围。

换句话说,虽然是的,编译器在这种情况下可能会发出警告,我同意,它也可能会发出警告,但它实际上只会对像这样的非常简单的玩具示例有帮助。

如果代码看起来像这样:

void foo(int* x){
    x[2]=0;     
}

或这样:

void foo(int i){
    int x[2];
    x[i]=0;
}

编译器将无能为力。这些情况更为常见。正如其他人已经提到的,C++ 编译器的最大问题之一是它们已经慢得要命。他们必须检查的每个新警告都会增加更多的开销。那么,是否值得为基本上只发生在像这样的小玩具示例中的错误添加警告呢?

至于为什么你的反应如此糟糕,也许答案就在你的问题中:

我认为这种失败未能警告 VC9 中的严重遗漏错误,(自从使用自动变量**!!!!!!** 以来更是如此)。谁能给我一个改变主意的严肃理由?

减少加载的语言。坚持使用一个感叹号。如果你听起来像是要烧断保险丝,那么人们会认为你愤怒,然后他们会告诉你你反应过度,你应该闭嘴。

The reason it doesn't warn about this is that it is very rarely useful. Looking at your code:

int main(){
    int x[2];
    x[2]=0;     
    return 0;
}

We see that the compiler in this case is able to issue a warning, but only because:

  • the array had not yet decayed to a pointer -- in other words, the size information is still available, and
  • you're using a compile-time constant expression to index into the array.

In most real-world code, these two conditions won't hold. The array will almost always be a pointer, in which case the compiler has no size information at all. And equally, you often use a runtime-determined value to index into the array. And again, if you do that, the compiler can't determine if you might go out of bounds.

In other words, while yes, the compiler could issue a warning in this case, and I agree, it might as well, but it would only actually help in very simple toy examples like this one.

If the code had looked like this instead:

void foo(int* x){
    x[2]=0;     
}

or this:

void foo(int i){
    int x[2];
    x[i]=0;
}

the compiler would have been helpless. And those cases are far more common. As has already been mentioned by others, one of the biggest problems with C++ compilers is that they're already slow as hell. Every new warning they have to check for adds more overhead. So is it worth it to add a warning for an error that basically only occurs in little toy examples like this?

As for why you got so bad responses, perhaps the answer is in your question:

I consider this failure to warn a SERIOUS error of omission in VC9,(even more so since an auto variable**!!!!**). Can anyone give me a serious reason to change my mind?

Cut down on the loaded language. Stick to a single exclamation mark. If you sound like you're about to blow a fuse, then people will assume that you are FURIOUS, and then they will tell you that you're overreacting, and that you should just shut up.

泪是无色的血 2024-08-10 19:11:06

因为,编译器不是你的保姆。

Because, the compiler is not your babysitter.

总以为 2024-08-10 19:11:06

有几件事可能值得注意:

  1. 除非您关闭所有优化,否则编译结果将一无所获。内存根本不会被写入 - 你可能还写过:

    #pragma warning(push,4)
    int main(){
        返回0;
    }
    #pragma 警告(弹出)
    
  2. 正如其他地方提到的,进行这样的分析很困难(如不可计算的尝试解决停止问题)。在进行优化时,只在分析容易的情况下进行优化是可以的。当您寻找警告时,需要在能够找到简单案例和让人们依赖警告之间进行权衡。什么时候可以停止发出警告?是的,通过常量偏移量访问的本地声明的变量是微不足道的 - 但由于微不足道,它也就不那么重要了。如果访问是在普通内联函数中怎么办?或者如果访问处于具有常量边界的 for 循环中?这些都很容易查找,但它们各自代表了一整套新的测试、可能的回归等...几乎没有什么好处(如果有的话)。

我并不是说这个警告没有用——它只是不像你想象的那么明确。

A couple things that might be worth noting:

  1. Unless you have all optimization turned off, this is going to compile away to nothing. The memory will not be written to at all - you might as well have written:

    #pragma warning(push,4)
    int main(){
        return 0;
    }
    #pragma warning(pop)
    
  2. As mentioned elsewhere, doing analysis like this is hard (as in non-computable-trying-to-solve-the-halting-problem). When doing optimizations, it's OK to only do them in the cases where the analysis is easy. When you're looking for warnings, there is a trade-off between being able to find the easy cases, and letting people get dependent on the warnings. At what point is it ok to stop giving the warnings? Yes the locally declared variable being accessed by a constant offset is trivial - but by virtue of being trivial, it's also less important. What if the access is in a trivially inlined function? Or if the access is in a for-loop with constant bounds? These are both easy enough to look for, but they each represent a whole new set of tests, possible regressions, etc... for very little benefit (if any).

I'm not saying that this warning isn't useful - it's just not as clear-cut as you seem to think it is.

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