问题
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?
回答1:
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.
Remember that
x[i]
andi[x]
are the same thing in C. You can even do"string"[2]
OR you can do2["string"]
and get the same result. Try it. And this is becausex[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.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.
回答2:
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.
回答3:
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.
回答4:
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.
回答5:
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.
回答6:
Because, the compiler is not your babysitter.
回答7:
A couple things that might be worth noting:
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)
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.
来源:https://stackoverflow.com/questions/1365276/this-compiles-without-a-warning-in-vc9-at-warning-level-4-why-would-one-not-con