Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

left-shifting a promoted operand (C99 6.5.7p4)

44 views
Skip to first unread message

Ersek, Laszlo

unread,
Mar 9, 2013, 3:36:57 PM3/9/13
to
Hi,

I'm quite sure this has come up before, so apologies for the probably
repeated question. I checked all three technical corrigenda for C99, and
the latest C11 draft (N1570).

Please consider the following:
- unsigned short: 16 value bits, no padding bits,
- int: 1 sign bit, 31 value bits, no padding bits,
- long long: 1 sign bit, 63 value bits, no padding bits

#include <stdio.h>

int
main(void)
{
unsigned short x;
long long res;

x = 0xFFFF;
res = x << 16;
(void)fprintf(stdout, "%lld\n", res);
return 0;
}

In "x << 16", "x" is promoted to "int", which is also the result type (C99
6.5.7p3). The right operand is 16, which is non-negative and less than the
width of "int" (= 32, promoted left operand).

p4:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits
are filled with zeros. If E1 has an unsigned type, the value of the
result is E1 × 2^E2, reduced modulo one more than the maximum value
representable in the result type. If E1 has a signed type and
nonnegative value, and E1 × 2^E2 is representable in the result type,
then that is the resulting value; otherwise, the behavior is undefined.

E1 is "x" here, and it has an unsigned type. The result is 65535 * 2^16,
reduced modulo INT_MAX+1 (2147483648), that is, hexadecimal 7FFF0000.

Unless of course p4 means

<not actual standard language>
The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits
are filled with zeros. If E1 has an unsigned type *AFTER PROMOTION*,
the value of the result is E1 × 2^E2, reduced modulo one more than the
maximum value representable in the result type. If E1 has a signed
*PROMOTED* type and nonnegative value, and E1 × 2^E2 is representable in
the result type, then that is the resulting value; otherwise, the
behavior is undefined.
</not actual standard language>

In that case the program invokes undefined behavior.

"gcc -std=c99 -pedantic" on x86_64 RHEL-6.4 seems to agree with the latter
meaning, the program prints -65536.

What is the intent of the cited paragraph? I assume omitting "... after
promotion ..." was an oversight.

Thank you,
Laszlo

James Kuyper

unread,
Mar 9, 2013, 5:52:32 PM3/9/13
to
No, that issue is covered by the first sentence of 6.5.7.p3, "The
integer promotions are performed on each of the operands." covers this
issue. Everything described in that paragraph after that sentence (and
the next two) occurs after the promotions, and therefore applies only to
the value and type of the two operands as they are, after the promotion.
This is generally true, wherever the promotions apply.
The same is true of the "usual arithmetic conversions" (of which the
integer promotions are just the first step, if applicable). For every
expression where the usual arithmetic conversions apply, the semantics
described for that expression are described in terms of the values and
types of the operands after those conversions.
It would add a great deal of unnecessary complexity to the standard to
add the phrases "after promotion" and "after the usual arithmetic
conversions" in every place where they apply. Simply making sure that
the description of each operator indicates when the
promotions/conversions occur for each operator was considered
sufficient. The standard isn't entirely consistent about this - the
phrases "after promotion", "promoted type" and "promoted operand" are
used - but not very often. However, I believe that there's a great many
places in the standard where those terms could be used without changing
the intended meaning.
--
James Kuyper

Ersek, Laszlo

unread,
Mar 9, 2013, 6:42:05 PM3/9/13
to
On Sat, 9 Mar 2013, James Kuyper wrote:

[snip]

> No, that issue is covered by the first sentence of 6.5.7.p3, "The
> integer promotions are performed on each of the operands." covers this
> issue. Everything described in that paragraph after that sentence (and
> the next two) occurs after the promotions, and therefore applies only to
> the value and type of the two operands as they are, after the promotion.

Thank you for explaining.
Laszlo

Hans-Bernhard Bröker

unread,
Mar 10, 2013, 11:36:31 AM3/10/13
to
On 09.03.2013 23:52, James Kuyper wrote:

> No, that issue is covered by the first sentence of 6.5.7.p3, "The
> integer promotions are performed on each of the operands." covers this
> issue. Everything described in that paragraph after that sentence (and
> the next two) occurs after the promotions, and therefore applies only to
> the value and type of the two operands as they are, after the promotion.

Does it, now? I see a problem here caused by the way those paragraphs
are worded, particularly the use of place-holders E1 and E2. I could
not find any proper definition of those anywhere --- they're just used
in multiple places, so I guess the committee must have believed their
meaning to be self-evident. As the question at hand shows, maybe
they're not.

So the document just says "the result of E1 << E2 is..." The
interpretation that E1 is exactly what formed the "shift-expression"
part of the grammar rule appears at least plausible. If that was not
the supposed meaning, there might need to be an explicit statement what
other meaning should apply.

> It would add a great deal of unnecessary complexity to the standard to
> add the phrases "after promotion" and "after the usual arithmetic
> conversions" in every place where they apply.

That complexity overhead could be massively reduced by just stating in
one central place (e.g. the chapter top text of 6.5) that placeholders
like "E1" are to be understood as the result of promotions and usual
arithmetic conversion, where applicable.

James Kuyper

unread,
Mar 10, 2013, 1:04:57 PM3/10/13
to
On 03/10/2013 11:36 AM, Hans-Bernhard Bröker wrote:
> On 09.03.2013 23:52, James Kuyper wrote:
>
>> No, that issue is covered by the first sentence of 6.5.7.p3, "The
>> integer promotions are performed on each of the operands." covers this
>> issue. Everything described in that paragraph after that sentence (and
>> the next two) occurs after the promotions, and therefore applies only to
>> the value and type of the two operands as they are, after the promotion.
>
> Does it, now? I see a problem here caused by the way those paragraphs
> are worded, particularly the use of place-holders E1 and E2. I could
> not find any proper definition of those anywhere --- they're just used
> in multiple places, so I guess the committee must have believed their
> meaning to be self-evident. As the question at hand shows, maybe
> they're not.
>
> So the document just says "the result of E1 << E2 is..." The
> interpretation that E1 is exactly what formed the "shift-expression"
> part of the grammar rule appears at least plausible.

Not really. After saying that the promotions are performed, the entire
rest of the semantics description is in terms of E1 and E2; if those
refer to the original expressions, rather than the expressions after
integer promotions have been performed, then the integer promotions have
no effect, because nothing in the rest of the description makes any use
of the result of those promotions. If that were the intent, what would
be the point of specifying that the integer promotions occur? I can't
see that as plausibly being the intent, though I could see it as a
plausible misinterpretation - and I wouldn't object to adding some
clarification to make such misinterpretation less likely.

>> It would add a great deal of unnecessary complexity to the standard to
>> add the phrases "after promotion" and "after the usual arithmetic
>> conversions" in every place where they apply.
>
> That complexity overhead could be massively reduced by just stating in
> one central place (e.g. the chapter top text of 6.5) that placeholders
> like "E1" are to be understood as the result of promotions and usual
> arithmetic conversion, where applicable.

I suppose that might help.
--
James Kuyper

Hans-Bernhard Bröker

unread,
Mar 10, 2013, 2:11:48 PM3/10/13
to
On 10.03.2013 18:04, James Kuyper wrote:
> On 03/10/2013 11:36 AM, Hans-Bernhard Bröker wrote:

>> So the document just says "the result of E1 << E2 is..." The
>> interpretation that E1 is exactly what formed the
>> "shift-expression" part of the grammar rule appears at least
>> plausible.

> Not really. After saying that the promotions are performed, the
> entire rest of the semantics description is in terms of E1 and E2;

But since the only hint of a definition of what E1 actually is, by lack
of any actual definition, is implied by its first usage in "E1 << E2",
then how could E1 be anything else but the first operand, verbatim?

> if those refer to the original expressions,

How could they not be, given they're defined only by example, as
elements of what looks 100% like the original expression? In a slightly
nasty, devil's advocate kind of mood, I might write

int32_t testfunc(void) {
unsigned char E1 = 255;
int E2 = 24;

return E1 << E2;
}

So if I can spell out exactly the same thing found in the Standard, and
yet their "E1" is supposed to mean something else than the "E1" I
actually wrote, there better be a very strong explanation for that.

Sequential ordering of paragraphs (mentioning promotion first, then
discussing values) doesn't really strike me as such a very strong
explanation, all by itself.

> If that were the intent, what would be the point of specifying that
> the integer promotions occur?

Oh, I don't doubt the intent. It's the presentation of it that I'm not
so sure about.

Joe keane

unread,
Mar 10, 2013, 9:59:06 PM3/10/13
to
In article <khgecj$urh$1...@dont-email.me>,
James Kuyper <james...@verizon.net> wrote:
>For every expression where the usual arithmetic conversions apply, the
>semantics described for that expression are described in terms of the
>values and types of the operands after those conversions.

Good luck with that!

int main(int argc, char **argv)
{
unsigned short x = 2;

printf("%d\n", sizeof (x << 1));
printf("%d\n", sizeof (x <<= 1));
return 0;
}

The short answer is that we don't want to promote the -operands-.

Tim Rentsch

unread,
Mar 15, 2013, 9:55:45 PM3/15/13
to
"Ersek, Laszlo" <la...@caesar.elte.hu> writes:

> [considering C99 6.5.7 p4, which includes ..]
>
> The result of E1 << E2 is E1 left-shifted E2 bit positions; [...]
> If E1 has an unsigned type, [...]
> If E1 has a signed type [...]

IMO this paragraph is misleading and/or ambiguous enough to merit
revising, or at least adding a clarifying footnote.

Tim Rentsch

unread,
Mar 15, 2013, 10:22:38 PM3/15/13
to
James Kuyper <james...@verizon.net> writes:

> On 03/09/2013 03:36 PM, Ersek, Laszlo wrote:
>> [In 6.5.7 p4, in reference to 'E1 << E2', does the phrase 'If E1
>> has an unsigned type' refer to the type before or after promotion?]
>
> No, that issue is covered by the first sentence of 6.5.7.p3, "The
> integer promotions are performed on each of the operands." covers
> this issue. Everything described in that paragraph after that
> sentence (and the next two) occurs after the promotions, [snip
> elaboration]

IMO this response is overly glib. M. Kuyper is presuming, as he
frequently does, that his interpretation is the most plausible or
only sensible one. The use of a syntactic form, 'E1 << E2', may
reasonably be taken to mean the reference is to the type of the
expressions, syntactically, rather than the type of the values
after promotion. I think it is clear, for other reasons, that the
meaning intended is to reference the types of the values after
promotion. But, for purposes of discussion in comp.std.c, which
exists largely to consider how the Standard might be read and how
it should be worded, the most appropriate conclusion is that this
paragraph reasonably allows several interpretations, and hence
would benefit from a clarifying revision.
0 new messages