making literals be a stdint size

Discussion in 'C Programming' started by Guest, Aug 25, 2003.

  1. Guest

    Guest 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?
     
    Guest, Aug 25, 2003
    #1
    1. Advertisements

  2. in comp.lang.c i read:
    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.
     
    those who know me have no need of my name, Aug 26, 2003
    #2
    1. Advertisements

  3. Guest

    Guest Guest

    | On 25 Aug 2003 22:37:01 GMT, 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?
     
    Guest, Aug 26, 2003
    #3
  4. Guest

    Guest Guest

    | In message <>
    | 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.
     
    Guest, Aug 26, 2003
    #4
  5. Guest

    Ben Pfaff Guest

    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.
    What if it does? I don't understand the problem you see.
     
    Ben Pfaff, Aug 26, 2003
    #5
  6. Guest

    Guest 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.
     
    Guest, Aug 27, 2003
    #6
  7. Guest

    Guest 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.
     
    Guest, Aug 28, 2003
    #7
  8. Guest

    Ben Pfaff Guest

    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.)
     
    Ben Pfaff, Aug 28, 2003
    #8
  9. Guest

    Guest Guest

    | 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.
     
    Guest, Sep 5, 2003
    #9
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.