integral constant suffixes vs. casts
Author 
Message 
David Libri #1 / 12

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 [09]+ and a possible preceding minus sign). I am trying to write conforming portable 64bit code, and the bewildering assortment of different 64bit 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 64bit printf format specifications, but that's another issue...)  David Librik 

Tue, 15 Mar 2005 01:33:00 GMT 


Kenneth Brod #2 / 12

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 [09]+ 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 16bit 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 


Douglas A. Gwy #3 / 12

integral constant suffixes vs. casts
Quote:
> (There's also a panoply of 64bit 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 


Mathew Hendr #4 / 12

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 16bit 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 


Dave Hans #5 / 12

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 [09]+ 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 16bit 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 


Barry Schwar #6 / 12

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 [09]+ 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 16bit 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 


Blair P. Hought #7 / 12

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 [09]+ 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: ansiisoiec98991999, 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 16bit 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 unsuffixed 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 


Peter Nilsso #8 / 12

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 16bit ints, 32768 is an unsigned int, but it's a long in C99.  Peter 

Sat, 19 Mar 2005 22:05:44 GMT 


Peter Nilsso #9 / 12

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 [09]+ 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 64bit code, and > the bewildering assortment of different 64bit 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 64bit printf format specifications, > but that's another issue...)
Which C99 attempts to address.  Peter 

Sat, 19 Mar 2005 22:05:51 GMT 


Dan P #10 / 12

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 16bit 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 


Kevin Brace #11 / 12

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 16bit 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 32bit, 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 C90type implementations with "long long" bolted on handled this is probably a hairy area.  Kevin Bracey http://www.braceygriffith.freeserve.co.uk/ 

Mon, 21 Mar 2005 08:13:54 GMT 


Dan P #12 / 12

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 16bit 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 32bit, 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 C90type 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 


