According to the published Rationale for the C Standard:
The terms unspecified behavior, undefined behavior, and implementation-defined behavior are used to categorize the result of writing programs whose properties the Standard does not, or cannot, completely describe. The goal of adopting this categorization is to allow a certain variety among implementations which permits quality of implementation to be an active force in the marketplace as well as to allow certain popular extensions, without removing the cachet of conformance to the Standard. [italics in original]
The Standard thus uses the term undefined behavior to refer both to constructs which would generally be meaningless on all implementations, and to constructs which some implementations will process as "popular extensions" but others may not.
Without knowing what your particular code is doing, it could be any of three situations:
Your code is relying upon a compiler to support a "popular extension", but in its present configuration it does not. Some such extensions were documented in the authoritative language specifications that predated the Standard (e.g. the 1974 "C Reference Manual", or K&R's "The C Programming Language", first and second editions) but weren't considered extensions at the time. Instead, judging from the Rationale, the authors of the Standard intended to say that compilers weren't required to behave precisely as earlier earlier specified in corner cases where doing so would be expensive and useless, and didn't think it necessary to explicitly say that compilers should nonetheless support the behaviors when practical and useful but expected compilers to do so whether mandated or not.
The code is accidentally doing something whose effects were never specified anywhere, and would thus be unpredictable.
The code is doing something which the Standard allows implementations to process in two or more different ways, chosen in Unspecified fashion (e.g. given x=f()+g();
, implementations are allowed to call f()
and then g()
, or to call g()
and then f()
, choosing in whatever manner they see fit), and its behavior is defined by the Standard or the implementation as performing in one of the ways it does.
In situations like yours, the problem is most often #1, #2, or a combination thereof, than #3. While #2 is perhaps more common than #1, compilers that value "optimization" above compatibility with existing code are making #1 increasingly common.