making literals be a stdint size

G

Guest

I have some code where I am using certain literal values cast to stdint types
like uint32_t, uint64_t, etc. In gcc versions below 3.3 it's working OK.

Here's an example:

(uint64_t) 0x5555555555555555U

In gcc 3.3.1, it doesn't like this, saying that the literal is out of range
for "unsigned long" (well, yeah, that would be true). What is the proper way
to write a literal when you want the type to be of a specific stdint type, as
opposed to the generic int types like long and long long? Is there even a
way to do it without a bunch of #if's to check sizes and figure out whether
to use L or LL appendage to the literal?
 
T

those who know me have no need of my name

in comp.lang.c i read:
(uint64_t) 0x5555555555555555U

In gcc 3.3.1, it doesn't like this, saying that the literal is out of range
for "unsigned long" (well, yeah, that would be true). What is the proper way
to write a literal when you want the type to be of a specific stdint type, as
opposed to the generic int types like long and long long?

in addition to kevin's response (use the macros, though they shouldn't be
necessary), which is right on the money, i'll add that since you don't
mention exact width types wider than 64 bits and since long long must be at
least 64 bits a suffix of ULL should also work for an extended-c90
compiler.
 
G

Guest

| On 25 Aug 2003 22:37:01 GMT, (e-mail address removed) wrote:
|
|>I have some code where I am using certain literal values cast to stdint types
|>like uint32_t, uint64_t, etc. In gcc versions below 3.3 it's working OK.
|>
|>Here's an example:
|>
|> (uint64_t) 0x5555555555555555U
|
| ITYM,
| 0x5555555555555555ULL
|
| Nick.

And if the cast size happens to be that of a long, not long long, on the
given platform, how does that affect it? And what if a platform has a
uintXX_t type which is larger than long long?
 
G

Guest

| In message <[email protected]>
| (e-mail address removed) wrote:
|
|> I have some code where I am using certain literal values cast to stdint
|> types like uint32_t, uint64_t, etc. In gcc versions below 3.3 it's working
|> OK.
|>
|> Here's an example:
|>
|> (uint64_t) 0x5555555555555555U
|>
|> In gcc 3.3.1, it doesn't like this, saying that the literal is out of range
|> for "unsigned long" (well, yeah, that would be true).
|
| It should still accept it. If it's too large for "unsigned long" then the
| type is "unsigned long long". This is covered in section 6.4.4.1 of C99.
|
| On reflection, that diagnostic makes it sound as if the compiler is in C90
| mode - check this. You really want to be in C99 mode if you want to use
| long longs in a coherent fashion.

I will double check that with the person who was compiling it. It worked by
default for me on gcc 3.2.2 but it failed for him by default on gcc 3.3.1.



|> What is the proper way to write a literal when you want the type to be of a
|> specific stdint type, as opposed to the generic int types like long and
|> long long?
|
| There are macros in <stdint.h> for this:
|
| UINT64_C(0x5555555555555555)
|
| This actually corresponds to uint_least64_t, although if you have a 64-bit
| type then obviously uint_least64_t == uint64_t.

I'll look into using these.


|> Is there even a way to do it without a bunch of #if's to check sizes and
|> figure out whether to use L or LL appendage to the literal?
|
| You shouldn't normally have to. Just write the constant (maybe with a U
| suffix to force unsigned), and the type will expand automatically to fit
| the constant - it will be int, long or long long. You only need to worry
| about L suffixes (or the _C macros) if you want to force the constant to be a
| larger type than it would otherwise be. For example, on a platform with
| 16-bit int, 32-bit long, 64-bit long long:
|
| 4000 int 4000L long int
| 40000 long int 400000L long int
| 4000000000 long long int 4000000000L long long int
|
| Decimal constants are always signed, unless they have a U suffix. Octal or
| hex constants are normally signed, unless they need to be unsigned to fit
| into a smaller type:
|
| 0x2000 int 0x2000U unsigned int
| 0x4000 int 0x4000U unsigned int
| 0x8000 unsigned int 0x8000U unsigned int
| 0x10000 long 0x10000U unsigned long
| 0x20000 long 0x20000U unsigned long
| 0x80000000 unsigned long 0x80000000U unsigned long
| 0x100000000 long long 0x100000000U unsigned long long
|
| For a C90 compiler with a long long extension, this is more complicated;
| C90's constant type rules do not include long long, so you have to mess
| with suffixes to override the standard C90 behaviour. Don't go there - use
| C99.
|
| In C99 it should be perfectly fine to write
|
| (..._t) 0x........
|
| with no suffix. The constant will automatically assume a suitable type to
| accurately represent the value, and the cast will convert the value to the
| required type. The only scope for failure is if the value doesn't actually
| fit in the specified type.

It fix under gcc 3.2.2 so it should be OK. Thanks for the leads. I'll dig
in and maybe report a bug to the gcc people if it continues to look like it.
 
B

Ben Pfaff

| On 25 Aug 2003 22:37:01 GMT, (e-mail address removed) wrote:
|
|>I have some code where I am using certain literal values cast to stdint types
|>like uint32_t, uint64_t, etc. In gcc versions below 3.3 it's working OK.
|>
|>Here's an example:
|>
|> (uint64_t) 0x5555555555555555U
|
| ITYM,
| 0x5555555555555555ULL
| ppp
| Nick.

And if the cast size happens to be that of a long, not long long, on the
given platform, how does that affect it?

0x5555555555555555 will fit into an unsigned long long. It will
also fit into a uint64_t. Casts preserve value, so there is no
problem that I see.
And what if a platform has a
uintXX_t type which is larger than long long?

What if it does? I don't understand the problem you see.
 
G

Guest

| in comp.lang.c i read:
|
|> (uint64_t) 0x5555555555555555U
|>
|>In gcc 3.3.1, it doesn't like this, saying that the literal is out of range
|>for "unsigned long" (well, yeah, that would be true). What is the proper way
|>to write a literal when you want the type to be of a specific stdint type, as
|>opposed to the generic int types like long and long long?
|
| in addition to kevin's response (use the macros, though they shouldn't be
| necessary), which is right on the money, i'll add that since you don't
| mention exact width types wider than 64 bits and since long long must be at
| least 64 bits a suffix of ULL should also work for an extended-c90
| compiler.

There are two issues:

1. If ULL is used, but long long is 128 bits on that platform,
the for a value only needing 64 bits, this might cause more
memory to be used to store the constant somewhere and convert
it in runnable code.

2. If long long is 64 bits, but the machine supports 128 bits,
and ther eis a uint128_t (in C99), then how to you express a
constant for that.

GCC 3.3.1 complains that (uint64_t) 0x5555555555555555U is too large for
unsigned long. Sure, I can make it be ULL. But I shouldn't have to.
I think GCC is broken. I just wanted to make sure.
 
G

Guest

| Now I am just confused. Where did a 128-bit type come into the
| picture. Your original question, as I understood it, was "how do
| I write a uint64_t constant". (uint64_t) 0x5555555555555555ULL
| is a way to do that.

The question is how do I write a constant (I used the wrong term
literal before) which is a specific stdint size, WITHOUT specifying
what size that is in terms of long or long long. The reason is so
I can make that constant portable.


| The ULL suffix isn't even necessary. 0x5555555555555555 is a
| valid constant of some integer type by itself; casting it to
| uint64_t will convert it into an uint64_t having the same value.

Then gcc 3.3.1 is broken. I had specified 0x5555555555555555U
with the cast in front of (uint64_t) and it said the value was out
of range for "unsigned long".


|> I want to know the officially/formally correct way to write the
|> constant in full 128 bit glory.
|> An earlier following said 6.4.4.1 of C99 requires a constant be
|> of a type that fits it. That should solve the problem I would
|> think. The catch is that gcc 3.3.1 is broken based on someone
|> I know compiling my library on their machine with gcc 3.3.1.
|
| Here is what 6.4.4.1 of C99 says about this. Maybe it will
| clarify the issue for you.
|
| $ The type of an integer constant is the first of the corresponding
| $ list in which its value can be represented.
| $
| $ Octal or Hexadecimal
| $ Suffix Decimal Constant Constant
| $
| $ none int int
| $ long int unsigned int
| $ long long int long int
| $ unsigned long int
| $ long long int
| $ unsigned long long int

[snip]

| $ If an integer constant cannot be represented by any type in its
| $ list, it may have an extended integer type, if the extended

OK, so this should work:

(uint128_t) 0x55555555555555555555555555555555U

on a platform where uint128_t is implemented, and long long is the same
size as uint64_t.

It was my goal to specify a number in terms of a specific size because it
involved playing with bits. And I not only didn't want to have to make the
code figure out if it was long long, I wante dto handle uintXX_t that was
not even equivalent to any traditional integer type.

A machine might have:
8 bits -> char, int8_t
16 bits -> short, int16_t
32 bits -> int, int32_t
64 bits -> long, int64_t
128 bits -> long long, int128_t
256 bits -> int256_t
I just want to have constants that adapt and GCC appeared broken but I wanted
to double check that first before pointing fingers.
 
B

Ben Pfaff

| The ULL suffix isn't even necessary. 0x5555555555555555 is a
| valid constant of some integer type by itself; casting it to
| uint64_t will convert it into an uint64_t having the same value.

Then gcc 3.3.1 is broken. I had specified 0x5555555555555555U
with the cast in front of (uint64_t) and it said the value was out
of range for "unsigned long".

Have you tried this while invoking GCC 3.3.1 in its "try to be
C99 compliant mode"? (It's a real question; I don't know what it
will do.)
 
G

Guest

| (e-mail address removed) writes:
|
|>
|> | The ULL suffix isn't even necessary. 0x5555555555555555 is a
|> | valid constant of some integer type by itself; casting it to
|> | uint64_t will convert it into an uint64_t having the same value.
|>
|> Then gcc 3.3.1 is broken. I had specified 0x5555555555555555U
|> with the cast in front of (uint64_t) and it said the value was out
|> of range for "unsigned long".
|
| Have you tried this while invoking GCC 3.3.1 in its "try to be
| C99 compliant mode"? (It's a real question; I don't know what it
| will do.)

Yes. It works that way. But then I have to make it so that option is not
used with older versions that don't understand it.

What seems to work fine overall is wrapping all the constants in the
INTxx_C() macros.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top