Is "-1>>5;" unspecified behavior in C?
Asked Answered
B

4

39

C11 §6.5.7 Paragraph 5:

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2*^E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

But, The viva64 reference document says:

int B;
B = -1 >> 5; // unspecified behavior

I ran this code on GCC and it's always give an output -1.

So, standard say's that "If E1 has a signed type and a negative value, the resulting value is implementation-defined", But that document say's that -1>>5; is unspecified behavior.

So, Is -1>>5; unspecified behavior in C? Which is correct?

Bagby answered 16/10, 2017 at 18:57 Comment(8)
If you're trying to write portable code, the distinction between implementation-defined and unspecified is not very significant, so code checkers treat them similarly.Kalgoorlie
It is is implementation-defined.Phototelegraphy
@chux So, that document is incorrect??Bagby
That document quotes the standard in its explanation.Kalgoorlie
This is not a dup. The given dup asks why right-shifting signed numbers works the way it does. This question is asking about the difference between unspecified and implementation defined. Reopening.Silver
The spec is always correctUse
Why is there a bounty added? The question already has lots of views and highly upvoted answersNarcose
I'd really tempted to replace gcc or bit-manipulation tag with language-lawyer. The former two are not essential to the question, while the latter is.Adiathermancy
S
39

Both are correct. Implementation defined behavior is a particular type of unspecified behavior.

Citing section 3.4.1 of the C standard which defines "implementation-defined behavior":

1 implementation-defined behavior

unspecified behavior where each implementation documents how the choice is made

2 EXAMPLE An example of implementation-defined behavior is the propagation of the high-order bit when a signed integer is shifted right.

From section 3.4.4 defining "unspecified behavior":

1 unspecified behavior

use of an unspecified value, or other behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance

2 EXAMPLE An example of unspecified behavior is the order in which the arguments to a function are evaluated.

As for GCC, you'll always get the same answer because the operation is implementation defined. It implements right shift of negative numbers via sign extension

From the GCC documentation:

The results of some bitwise operations on signed integers (C90 6.3, C99 and C11 6.5).

Bitwise operators act on the representation of the value including both the sign and value bits, where the sign bit is considered immediately above the highest-value value bit. Signed >> acts on negative numbers by sign extension.

As an extension to the C language, GCC does not use the latitude given in C99 and C11 only to treat certain aspects of signed << as undefined. However, -fsanitize=shift (and -fsanitize=undefined) will diagnose such cases. They are also diagnosed where constant expressions are required.

Silver answered 16/10, 2017 at 19:2 Comment(8)
This is not quite correct: "Implementation defined behavior is a particular type of unspecified behavior". If a behavior is implementation-defined, the standard is specifying that the implementation must define and document it, so it's not unspecified. Unspecified behavior is for situations where the implementation is free to choose but does not have to document a behavior or make it consistent.Elea
@R.. Except the definition of "implementation-defined behavior" actually uses the exact words "unspecified behavior". I guess requiring documentation is not considered imposing "further requirements on which is chosen".Lysol
I would interpret the definition of "implementation-defined behaviour" that you quoted as being exclusive of "unspecified behaviour", i.e. meaning "as for unspecified behaviour, but also with this requirement". After all, the definition of "unspecified behaviour" includes "imposes no further requirements on which is chosen", however implementation-defined behaviour does impose a requirement that the implementation document the choice, therefore it does not meet the definition of "unspecified behaviour"Narcose
@Narcose implementation-specified behaviour says: "documents on how the choice is made" - so an implementation can document it as "at random" and conform to the standard, and it is indistinguishable from any other undefined behaviour.Selene
I provide further evidence, a DR to C89 :)Selene
@AnttiHaapala: I hadn't seen that one. However, the C89 Rationale does say "While a deficient implementation could probably contrive a program that meets this requirement, yet still succeed in being useless, the C89 Committee felt that such ingenuity would probably require more work than making something useful." Thus, most questions about whether the Standard allowed a conforming implementation to behave in some obtuse fashion should have been answered "The Standard would probably allow a garbage-quality-but-conforming implementation to behave that way. So?" Too bad they weren't.Thermotherapy
@AnttiHaapala: That's not to suggest that all such questions are about behaviors that would generally be obtuse. Most of them concern behaviors that would be sensible in some cases but obtuse in others. Unfortunately, the authors of the Standard, in replying to such questions, fail to make clear that the Standard often gives permission to behave a certain way in cases where it is obtuse as well as those where it is sensible; they expect that people writing seeking to write quality implementations for a particular purpose will be able to judge which cases are which.Thermotherapy
Since evidently this thing is shambling back to life, or at least undeath, I'm inclined to agree with aschepler. The natural reading of "unspecified behavior where [...]" in the definition of implementation-defined behavior is that implementation-defined behavior is a sub-category of unspecified behavior. For example, if I say "a sack race is a race where every participant has their legs and lower torso in a large sack", I mean a sack race is a specific kind of race, not that a sack race isn't actually a race, but only like one.Komi
H
14

"Unspecified behavior" and "implementation defined" are not contradictory. It just means that the C standard does not specify what needs to happen, and that various implementations can do what they deem "correct."

Running it multiple times on one compiler and getting the same result only means that that particular compiler is consistent. You may get different results on a different compiler.

Hoyt answered 16/10, 2017 at 19:2 Comment(6)
Neither term is a subset of the other. If an action invokes "unspecified" behavior, implementations are required to choose from among a finite set of choices (e.g. x()+y() must behave as though it either fully evaluates x() and then evaluates y(), or fully y() and then x(); those are the only two choices). If an action invokes "Implementation-Defined" behavior, implementations are required to document a specific behavior, but could do just about anything they like so long as they document it.Thermotherapy
@Thermotherapy it says "document how the choice is made, not document which behaviour was chosen".Selene
@AnttiHaapala: I don't think "Implementation-Defined" is intended as an invitation for implementations to simply say "This implementation selects among these behaviors unpredictably". The Standard poses no hard requirements upon the quality of implementations' documentation, but I think the clear implication would be that only low-quality implementations would fail to say something useful.Thermotherapy
@supercat, I'm not seeing what in the definition of "unspecified behavior" requires the behavior to be chosen from a finite set of choices, unless it's that computers can represent only a finite number of distinct states. "Two or more" does not convey finiteness to me.Komi
@JohnBollinger: The places in the Standard where I've noticed the term used describe things that would have a finite number of choices, such as the order in which various operations are performed, or the values left in padding bytes of a structure when preceding members are written. It might have been possible and appropriate for Standard to use the term in cases where there might be an infinite number of possible behaviors that were all quite similar (e.g. saying that if an implementation pre-defines a certain macro, the behavior of integer overflow would be limited to yielding a value...Thermotherapy
...that behaves like any mathematical integer which is congruent to the correct value, mod the range of the integer type. Since there would be a countably infinite number of such values, there would thus be a countably infinite number of possible behaviors). I don't know of anyplace the Standard actually refers to "unspecified" behaviors, however, where it does not also specify a finite number of possibilities. Is there anyplace it does so that I haven't noticed?Thermotherapy
G
2

Implementation-defined behaviour is a subclass of unspecified behaviour, i.e. behaviour that is not specified by the standard.

Defect Report #154 to C89 asked the committee what are the limits to the implementation-defined behaviour; the committee answers that an implementation can define any behaviour it wants, and that does not need to be constant.

What an implementation needs to do, is to document how this choice is made, as opposed to the other class of unspecified behaviour where a conforming implementation need not even bother telling how the choice is made, possibly because for these the majority of implementations the text would say "at random" or "depending on the compiler optimization level" or "depending on the register allocation for local variables".

Gablet answered 27/8, 2018 at 9:16 Comment(2)
The Standard avoids using the term "implementation-defined behavior" in cases where any significant number of quality implementations would have been expected to say "at random". The threshold between UB and IDB seems to generally be whether the authors of the Standard envisioned any plausible situations where some implementation might be unable to specify anything useful. Consider the behavior of -1<<x. It was defined under C89, but became UB under C99 even though nearly all implementations behaved the same way. If IDB were an invitation to say "at random", then nearly all forms...Thermotherapy
...of UB could just as easily be IDB, but the possibility that there might exist some implementation where it might be hard to document a consistent behavior for -1<<x seems to have been adequate justification for making such action invoke UB rather than treating it as IDB [the C99 rationale doesn't even mention the change, much less give a reason for it].Thermotherapy
D
2

I don't get any of the present answers. The C standard clearly says that right-shifting a negative number is implementation-defined behavior. It is not unspecified behavior, which means something else. As you correctly cite (C17 6.5.7 §5):

The result of E1 >> E2 is E1 right-shifted E2 bit positions. /--/
If E1 has a signed type and a negative value, the resulting value is implementation-defined.

This means that the compiler must document how it behaves. Period.

In pratice: the document must tell if the compiler uses arithmetic right shift or logical right shift.


This is as opposed to unspecified behavior, which is implementation-specific behavior that does not need to be documented. Unspecified behavior is used in two cases:

  • When the compiler behavior might be an implementation secret that the compiler vendor should not be forced to reveal to their competitors.
  • When the compiler can't be bothered to document how the underlying details such as OS and RAM memory cells work.

For example, a compiler does not need to document the order of evaluation in code like this:

a  = f1() + f2();
a += f1() + f2();

Documenting the order in which the sub-expressions are evaluated would reveal details about how the compiler's internal expression tree and optimizer work, which in turn would reveal why a compiler produces better code or compiles faster than the competition. This was a big thing when the C standard was originally written. Less so nowadays when there's some great open-source compilers, so it is no longer a secret.

Similarly, a compiler does not need to document what this code prints:

int a;
int ptr = &a;
printf("%d", *ptr);

a is an indeterminate value and the output is unspecified - in practice the output depends on what was stored in that particular RAM cell before. What we would call a "garbage value". (Before yelling "UB", see (Why) is using an uninitialized variable undefined behavior?).

Decrement answered 30/8, 2018 at 9:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.