I\'m searching the C90 standard for things to be aware of, when writing hignly portable code, while having low trust in the good will of the compile
I believe the behavior is undefined.
The standard requires a diagnostic for any translation unit that violates a constraint or syntax rule (N1570 5.1.1.3), and may not successfully translate a translation unit that contains a #error
directive that survives the preprocessing phase (n1570 4, paragraph 4). (N1570 is a draft of the C11 standard, but this is the same across C90, C99, and C11, except that #error
was added by C99.)
All constraints and syntax rules are specified explicitly in the standard. Exceeding an implementation-defined limit violates neither a constraint nor a syntax rule. It's sufficiently obvious, I think, that an implementation is not required to successfully process an otherwise correct program that exceeds a translation limit, but the standard says nothing about how it should respond to such a violation. Therefore, the behavior is undefined by omission.
(An implementation of decent quality would issue a diagnostic saying that a limit has been exceeded, but this is not required by the standard.)
To answer the third part of your question, no, I haven't heard of a static checker tool that checks programs for violations of the minimum translation limits. Such a tool could be quite useful, and probably wouldn't be too difficult to write once you have a C parser. For the limit on the size of an object (32767 bytes in C90, 65535 bytes in C99 and C11), it would have to know how the compiler determines object sizes; int arr[30000];
may or may not exceed 65535 bytes, depending on sizeof (int)
. I wouldn't be too surprised if someone has already implemented such a tool and I just haven't heard of it.
Note that most implementations do not impose the fixed limits that the standard permits; rather, any limits are imposed by the memory resources available at compile time.
The standard does present the translation limits in a rather odd way. I'm thinking in particular of the clause that says:
The implementation shall be able to translate and execute at least one program that contains at least one instance of every one of the following limits:
(that's section 5.2.4.1 in C90, C99, and C11). So a perverse implementation could accept exactly one program and reject all others.
The point, I think is that specifying reasonable limits that all implementations must meet would be impractical. The standard could say that all implementations must always accept objects of at least 32767 bytes -- but what about a program that defines a million such objects? The limits interact with each other in extremely complex ways, and the nature of the interaction depends on the internal structure of each compiler. (If you think you can define the requirements for translation limits better than the C standard does so, I encourage you to try it.)
Instead, the standard states the requirements in such a way that the easiest way to implement a useful compiler that obeys the letter of the standard is to implement a useful compiler that obeys the spirit of the standard, by not imposing any unreasonable limits. A useless compiler that meets the letter of the standard is possible but irrelevant; I don't know that anybody has ever implemented such a thing, and I'm sure nobody would attempt to use it.