integral constant suffixes vs. casts 
Author Message
 integral constant suffixes vs. casts

Are there instances where an integral constant suffix on
a constant produces a different value than casting that
constant to the equivalent type?

For instance, can #####L be different than ((long)#####) ?
(Where ##### denotes [0-9]+ and a possible preceding minus sign).

I am trying to write conforming portable 64-bit code, and
the bewildering assortment of different 64-bit types has
led me to insulate the system dependencies behind typedefs --
so I use defined types like Bit64 and UBit64, instead of
(unsigned) long or long long or __int64 or int64_t.  But
there's a equally large number of ways to mark integral
constants (L, LL, I64...), so it'd be nice to know if I can
write ((Bit64)-1) in place of -1L.  (I get nervous about
sign extension here.)

(There's also a panoply of 64-bit printf format specifications,
but that's another issue...)

- David Librik
--



Tue, 15 Mar 2005 01:33:00 GMT  
 integral constant suffixes vs. casts
Quote:

> Are there instances where an integral constant suffix on
> a constant produces a different value than casting that
> constant to the equivalent type?

> For instance, can #####L be different than ((long)#####) ?
> (Where ##### denotes [0-9]+ and a possible preceding minus sign).

[...]

My understanding is "yes, they are different".  (I'm sure someone can
quote chapter and verse.)

Suppose you are using a compiler targeted for a system where int's are
16 bits, and long's are 32 bits.

    The value 65537L represents the long value 65537.

    The value (long)65537 may (must?) generate a diagnostic, as
    65537 cannot fit into a 16-bit integer.

As a second example:

    65535L versus (long)65535

    While 65535 can fit into an _unsigned_ int, it cannot fit
    into an "int".  I don't know if the standard would allow it,
    but I can see a case where you end up with -1L as the value
    of the second example, as the bit pattern for (unsigned)65535
    is the same as (signed)-1.

--

+---------+----------------------------------+-----------------------------+
| Kenneth |     kenbrody at spamcop.net      | "The opinions expressed     |
|    J.   |    http://www.hvcomputer.com     |  herein are not necessarily |
|  Brody  |      http://www.fptech.com       |  those of fP Technologies." |
+---------+----------------------------------+-----------------------------+
--



Tue, 15 Mar 2005 23:37:34 GMT  
 integral constant suffixes vs. casts

Quote:

> (There's also a panoply of 64-bit printf format specifications,
> but that's another issue...)

Actually it's the same issue, and already addressed by the recent
standard headers <stdint.h> and <inttypes.h>.  An early implementation
of these is available for free at the Lysator C site, for example.
--



Tue, 15 Mar 2005 23:37:51 GMT  
 integral constant suffixes vs. casts


Quote:
>Suppose you are using a compiler targeted for a system where int's are
>16 bits, and long's are 32 bits.

>    The value 65537L represents the long value 65537.

>    The value (long)65537 may (must?) generate a diagnostic, as
>    65537 cannot fit into a 16-bit integer.

If 65537 can't be represented as int, then 65537 has type long int.
See C99 6.4.4.1, which I think is essentially the same as what was in
C90, only expanded to cover the new integer types.

-- Mat.
--



Thu, 17 Mar 2005 12:55:10 GMT  
 integral constant suffixes vs. casts


Quote:

>> Are there instances where an integral constant suffix on
>> a constant produces a different value than casting that
>> constant to the equivalent type?

>> For instance, can #####L be different than ((long)#####) ?
>> (Where ##### denotes [0-9]+ and a possible preceding minus sign).
>[...]

>My understanding is "yes, they are different".  (I'm sure someone can
>quote chapter and verse.)

In n869, it's 6.4.4.1p5 and 6.5.4p4   ;-)

Quote:

>Suppose you are using a compiler targeted for a system where int's are
>16 bits, and long's are 32 bits.

>    The value 65537L represents the long value 65537.

>    The value (long)65537 may (must?) generate a diagnostic, as
>    65537 cannot fit into a 16-bit integer.

No.  There is no difference between 65537L and 65537 in the
implementation you propose.  Both are of type long int.  The cast in
(long)65537 is redundant.  A diagnostic is not allowed.

Quote:

>As a second example:

>    65535L versus (long)65535

>    While 65535 can fit into an _unsigned_ int, it cannot fit
>    into an "int".  I don't know if the standard would allow it,

Therefore 65535 is a long.  

Quote:
>    but I can see a case where you end up with -1L as the value
>    of the second example, as the bit pattern for (unsigned)65535
>    is the same as (signed)-1.

You've got it backwards.  "1L" is a constant, to which the unary minus
is applied.  The value will be the same as ((long)-1)

There is a difference between 0177777 and 65535: the former is
unsigned int, the latter is long int.  Decimal integer constants
without a suffix are the smallest signed integer type (int, long, or
long long) into which they fit.  Octal and hex constants without a
suffix will move to an unsigned type if they can fit in that.
Obviously, 0177777L is also long int, as is ((long)0177777).  

The difference between the cast and the suffix is is that the cast is
an operator and implies a conversion of the constant to the specified
type.  The suffix specifies the type of the constant itself.  I can't
think of any case offhand where the result would be different, except
maybe ((unsigned)-1) and (-1U).  I know what the first is, I'm not
sure about the second.

Regards,

                               -=Dave
--
Change is inevitable, progress is not.
--



Thu, 17 Mar 2005 12:55:26 GMT  
 integral constant suffixes vs. casts


Quote:

>> Are there instances where an integral constant suffix on
>> a constant produces a different value than casting that
>> constant to the equivalent type?

>> For instance, can #####L be different than ((long)#####) ?
>> (Where ##### denotes [0-9]+ and a possible preceding minus sign).
>[...]

>My understanding is "yes, they are different".  (I'm sure someone can
>quote chapter and verse.)

>Suppose you are using a compiler targeted for a system where int's are
>16 bits, and long's are 32 bits.

>    The value 65537L represents the long value 65537.

>    The value (long)65537 may (must?) generate a diagnostic, as
>    65537 cannot fit into a 16-bit integer.

Well I can quote the verse but it disproves your conclusion.  65537 is
an integer constant but not an int.  In section 6.4.4.1, paragraph 5,
the standard states "The type of an integer constant is the first of
the corresponding list in which its value can be represented."  (The
referenced list follows and starts with int and progress down to long
long in order of increasing size.)  Since the 65537 does not fit in an
int it has type long.  This has the side effect of making the cast and
suffix irrelevant.

<<Remove the del for email>>
--



Thu, 17 Mar 2005 12:55:31 GMT  
 integral constant suffixes vs. casts

Quote:

>> Are there instances where an integral constant suffix on
>> a constant produces a different value than casting that
>> constant to the equivalent type?

>> For instance, can #####L be different than ((long)#####) ?
>> (Where ##### denotes [0-9]+ and a possible preceding minus sign).
>[...]

>My understanding is "yes, they are different".  (I'm sure someone can
>quote chapter and verse.)

I just happen to have both.

Chapter:  ansi-iso-iec-9899-1999, section 6.4.4.1

Verse: "The type of an integer constant is the first of the
corresponding list in which its value can be represented."
[Which is followed by a big table of most of the integer
types.]

In particular, for decimal constants with no suffix, the table
goes,

int
long int
long long int

Quote:
>Suppose you are using a compiler targeted for a system where int's are
>16 bits, and long's are 32 bits.

>    The value 65537L represents the long value 65537.

>    The value (long)65537 may (must?) generate a diagnostic, as
>    65537 cannot fit into a 16-bit integer.

>As a second example:

>    65535L versus (long)65535

>    While 65535 can fit into an _unsigned_ int, it cannot fit
>    into an "int".  I don't know if the standard would allow it,
>    but I can see a case where you end up with -1L as the value
>    of the second example, as the bit pattern for (unsigned)65535
>    is the same as (signed)-1.

In both examples, since the un-suffixed number can not fit into
an int, it is interpreted as a long int before you cast it.

What this shows is that the suffixes are superfluous on numbers
that fit into the type you expect them to fit into.  You need them
only to force smaller numbers to be interpreted as wider types,
or as unsigned.

And now the twist.  The table for hex and octal is
different from the one for decimal:

int
unsigned int
long int
unsigned long int
long long int
unsigned long long int

So 65535 is long int, but 0xffff is unsigned int,
on your system.

Adding the suffix specifies the minimum width of the
constant.  If the number is too big for the type you
think of when you see the suffix, it is interpreted as
the type farther down the table that it does fit into.
Hex and octal numbers with "signed" suffixes can end up
unsigned.  Any numbers with "unsigned" suffixes can only
be interpreted as unsigned.

The only integral number the compiler should reject as a constant
is one that it can not represent in its widest integer type.

But your compiler may have "extended" integer types, which
the standard allows.  "extended" means it can be anything
you want that walks and quacks like an integer type.

I think I've stated everything correctly here, but anyone
relying on me as the standard is nuts.  Regardless, my
answer to the original question is:

(long)<decimal number> is different from <decimal number>'L',
in those cases where the cast truncates the number.

(long)<hex or octal number> is different from <hex or
octal number>'L' in those cases where the cast truncates
the number or converts it from unsigned to signed.

                                --Blair
                                  "I could've bought a scanner and
                                   OCR'd the thing faster..."

P.S.  Just for fun, the standard doesn't care what
case the suffix letters are.  uLL is the same as UlL.
Just for fun.
--



Sat, 19 Mar 2005 21:55:59 GMT  
 integral constant suffixes vs. casts
....

Quote:
> If 65537 can't be represented as int, then 65537 has type long int.
> See C99 6.4.4.1, which I think is essentially the same as what was in
> C90, only expanded to cover the new integer types.

It has changed in that an unadorned decimal constant cannot be a standard
unsigned type. On a C90 implementation with 16-bit ints, 32768 is an
unsigned int, but it's a long in C99.

--
Peter
--



Sat, 19 Mar 2005 22:05:44 GMT  
 integral constant suffixes vs. casts

Quote:
> Are there instances where an integral constant suffix on
> a constant produces a different value than casting that
> constant to the equivalent type?

> For instance, can #####L be different than ((long)#####) ?

Yes, the latter is not usable within conditional preprocessor directives.

Quote:
> (Where ##### denotes [0-9]+ and a possible preceding minus sign).

The minus sign (unary negation) is an operator and forms a separate token
from the constant, unlike the suffixes like L.

Quote:
> I am trying to write conforming portable 64-bit code, and
> the bewildering assortment of different 64-bit types has
> led me to insulate the system dependencies behind typedefs --
> so I use defined types like Bit64 and UBit64, instead of
> (unsigned) long or long long or __int64 or int64_t.  But
> there's a equally large number of ways to mark integral
> constants (L, LL, I64...), so it'd be nice to know if I can
> write ((Bit64)-1) in place of -1L.  (I get nervous about
> sign extension here.)

Sign extension is a term applied to representations. I think you can calm
your nerves by knowning that the preservation of value is guaranteed across
different integer types whenever the value is representable in both types
involved.

Quote:

> (There's also a panoply of 64-bit printf format specifications,
> but that's another issue...)

Which C99 attempts to address.

--
Peter
--



Sat, 19 Mar 2005 22:05:51 GMT  
 integral constant suffixes vs. casts

Quote:


>>Suppose you are using a compiler targeted for a system where int's are
>>16 bits, and long's are 32 bits.

>>    The value 65537L represents the long value 65537.

>>    The value (long)65537 may (must?) generate a diagnostic, as
>>    65537 cannot fit into a 16-bit integer.

>No.  There is no difference between 65537L and 65537 in the
>implementation you propose.  Both are of type long int.  The cast in
>(long)65537 is redundant.  A diagnostic is not allowed.

                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A diagnostic is *always* allowed, even if the code in question doesn't
require one.

Dan
--
Dan Pop
DESY Zeuthen, RZ group

--



Sat, 19 Mar 2005 22:05:56 GMT  
 integral constant suffixes vs. casts


Quote:

> ....
> > If 65537 can't be represented as int, then 65537 has type long int.
> > See C99 6.4.4.1, which I think is essentially the same as what was in
> > C90, only expanded to cover the new integer types.

> It has changed in that an unadorned decimal constant cannot be a standard
> unsigned type. On a C90 implementation with 16-bit ints, 32768 is an
> unsigned int, but it's a long in C99.

That's not quite right. 32768 is a long int in both cases. The difference in
unadorned decimal constants occurs higher up - if long is 32-bit, then
3,000,000,000 is an unsigned long int in C90, but is a long long int in
C99.

In detail, the list for unadorned decimal constants has changed thus:

     C90                  C99
     ---                  ---
     int                  int
     long int             long int
     unsigned long int    long long int
                          <larger signed extended integer types>

Quite how C90-type implementations with "long long" bolted on handled this is
probably a hairy area.

--
Kevin Bracey
http://www.bracey-griffith.freeserve.co.uk/
--



Mon, 21 Mar 2005 08:13:54 GMT  
 integral constant suffixes vs. casts

Quote:



>> ....
>> > If 65537 can't be represented as int, then 65537 has type long int.
>> > See C99 6.4.4.1, which I think is essentially the same as what was in
>> > C90, only expanded to cover the new integer types.

>> It has changed in that an unadorned decimal constant cannot be a standard
>> unsigned type. On a C90 implementation with 16-bit ints, 32768 is an
>> unsigned int, but it's a long in C99.

>That's not quite right. 32768 is a long int in both cases. The difference in
>unadorned decimal constants occurs higher up - if long is 32-bit, then
>3,000,000,000 is an unsigned long int in C90, but is a long long int in
>C99.

>In detail, the list for unadorned decimal constants has changed thus:

>     C90                  C99
>     ---                  ---
>     int                  int
>     long int             long int
>     unsigned long int    long long int
>                          <larger signed extended integer types>

The thing that confuses people is the asymmetry between decimal constants
and the octal and hexadecimal ones.  The latter use an extended list:
int, unsigned int, long int, unsigned long int (in C89).

IMHO, it would have been more sensible for the octal and hexadecimal
constants to have only unsigned types.

Quote:
>Quite how C90-type implementations with "long long" bolted on handled this is
>probably a hairy area.

Well, gcc gets it wrong even when invoked in C99 mode:

    fangorn:~/tmp 747> cat test.c
    #include <stdio.h>

    int main()
    {
        printf("%lld\n", 4000000000);
        return 0;
    }
    fangorn:~/tmp 748> gcc -Wall -std=c99 test.c
    test.c: In function `main':
    test.c:5: warning: decimal constant is so large that it is unsigned
    test.c:5: warning: long long int format, different type arg (arg 2)

There is no way 4000000000 could be an unsigned constant under the C99
rules for decimal constants.  Since 4000000000 is too large for a long
int (on the platform I've compiled this program), its type should have
been long long int, which is what the printf call expects.  Of course,
the program produces the wrong output when executed:

    fangorn:~/tmp 749> ./a.out
    -4611700067560380416

because the compiler passed an unsigned long value to printf, instead of a
long long.

Dan
--
Dan Pop
DESY Zeuthen, RZ group

--



Wed, 23 Mar 2005 06:02:01 GMT  
 
 [ 12 post ] 

 Relevant Pages 

1. Integer constants - use of 'u' suffixes

2. Suffixes For Constants, ANSI C

3. constant integral expression

4. constant integral expression

5. newbie = non-integral-constant static?

6. Symbolic Constants vs. Enumeration Constants

7. Make problem with .SUFFIXES and suffix rules

8. old style casts vs new style casts

9. char[] vs char * vs #defines for constant strings

10. old style casts vs new style casts

11. Are casts constants?

12. ignorant question: const vs #define constants

 

 
Powered by phpBB® Forum Software