Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
428 views
in Technique[技术] by (71.8m points)

c - Is "char foo = 255" undefined behavior if char is signed?

The following doesn't give me any warning whatsoever when compiled with gcc 4.5.2 on x86 machine with Linux:

char foo = 255;

But when I use -pedantic, gcc says:

warning: overflow in implicit constant conversion

The way gcc acts is a tad strange and it makes me doubt if I really understand what's going on in this assignment. I think that if char is 8 bit long on POSIX and it's signed by default, it can't hold 255.

In C standard, it says that unsigned integer overflow results in overflow, but signed integer overflow is undefined. So is this assignment undefined behavior? And why does gcc act this way?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Summary: The result is implementation-defined and very likely to be -1, but it's complicated, at least in principle.

The rules regarding overflow are different for operators vs. conversions, and for signed types vs. unsigned types -- and the conversion rules changed between C90 and C99.

As of C90, overflow of an operator with signed integer operands ("overflow" meaning that the mathematical result cannot be represented in the expression's type) has undefined behavior. For unsigned integer operands, the behavior is well defined as the usual wraparound (strictly speaking the standard doesn't call this an "overflow"). But your declaration:

char foo = 255;

doesn't use any operators (the = is an initializer, not an assignment), so none of that applies in this case.

If type char can represent the value 255 (which is true either of plain char is unsigned or if CHAR_BIT >= 9), then of course the behavior is well defined. The int expression 255 is implicitly converted to char. (Since CHAR_BIT >= 8, it's not possible for this particular case to invoke unsigned wraparound.)

Otherwise, the conversion yields a result that can't be stored in a char.

As of C90, the result of the conversion is implementation-defined -- which means that it's guaranteed to set foo to some value within the range of type char, and you can determine what that value is by reading the implementation's documentation, which is required to tell you how the conversion works. (I've never seen an implementation where the stored value is anything other than -1, but any result is possible in principle.)

C99 changed the definition, so that an overflowing conversion to a signed type either yields an implementation-defined result or raises an implementation-defined signal.

If a compiler chooses to do the latter, then it must document which signal is raised.

So what happens if an implementation-defined signal is raised? Section 7.14 of the standard says:

The complete set of signals, their semantics, and their default handling is implementation-defined

It's not entirely clear (to me) what the range of possible behaviors for the "default handling" of signals is. In the worst case, I suppose such a signal could terminate the program. You might or might not be able to define a signal handler that catches the signal.

7.14 also says:

If and when the function returns, if the value of sig is SIGFPE, SIGILL, SIGSEGV, or any other implementation-defined value corresponding to a computational exception, the behavior is undefined; otherwise the program will resume execution at the point it was interrupted.

but I don't think that applies, since an overflowing conversion is not a "computational exception" as the term is used here. (Unless the implementation-defined signal happens to be SIGFPE, SIGILL, or SIGSEGV -- but that would be silly).

So ultimately, if an implementation chooses to raise a signal in response to an overflowing conversion, the behavior (not just the result) is at least implementation-defined, and there might be circumstances in which it could be undefined. In any case, there doesn't seem to be any portable way to deal with such a signal.

In practice, I've never heard of an implementation that takes advantage of the new wording in C99. For all compilers I've heard of, the result of the conversion is implementation-defined -- and very probably yields what you'd expect from a 2's-complement truncation. (And I'm not at all convinced that this change in C99 was a good idea. If nothing else, it made this answer about 3 times as long as it would otherwise have needed to be.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...