9

I have to define constants like this :

#define MY_CONSTANT   0xBEEF

I want to be sure that my constant will be considered 32 bits.

I have can use a (uint32_t) cast like this :

#define MY_CONSTANT   (uint32_t)0xBEEF

Or a UL suffix like this :

#define MY_CONSTANT   0xBEEFUL

Are these two versions fully equivalent?

I would say no, as UL is the equivalent of unsigned long and unsigned long length may depend on CPU.

The C99 standard ensures that an uint32_t integer is 32 bits, but I don't think it ensures that a UL suffix does the same.

unwind
  • 391,730
  • 64
  • 469
  • 606
ermitz
  • 121
  • 1
  • 4
  • 1
    @EOF `UINT32_C()` will insure the type is _at least_ 32 bit as in type `uint_least32_t` – chux - Reinstate Monica Feb 18 '16 at 16:07
  • 1
    If you have a compiler with a 16-bit `int`, then your constant will be sign extended when not marked as unsigned (or an implementation-defined conversion will take place). You should use a `U` suffix. – Doug Currie Feb 18 '16 at 16:33
  • 1
    In a few years (???) `UL` will still work, but `(uint32_t)` may not work because it's a optional type that need not exist on platforms where it does not make sense (see [7.20.1.1p3](http://port70.net/~nsz/c/c11/n1570.html#7.20.1.1)). – pmg Feb 18 '16 at 16:41
  • @chux: right. Could you point to a situation where this would be a problem? – EOF Feb 18 '16 at 17:33
  • @EOL With `UINT32_C(0xBEEF)`, `sizeof(MY_CONSTANT) == sizeof(uint32_t)` could fail. Using `UINT32_C()` does not meet OP's goal of "my constant will be considered 32 bits.". Otherwise OP might as well use `0xBEEFUL`. – chux - Reinstate Monica Feb 18 '16 at 17:57
  • @chux: The only way `sizeof(UINT32_C(0xBEEF)) != sizeof(uint32_t)` is if `uint32_t` doesn't exist. In that case, I presume the compilation will fail with a diagnostic, which would happen *anyway* if you cast to `(uint32_t)`. – EOF Feb 18 '16 at 21:14
  • @EOL Agree that the example code given is broke. So how about `printf("%" PRIu32, UINT32_C(0xBEEF))`? or `if (UINT32_C(0xBEEF) << 16)`? Can you think of some? – chux - Reinstate Monica Feb 18 '16 at 21:30
  • @chux: The `printf("%" PRIu32, UINT32_C(0xBEEF))` would not compile due to `PRIu32` not being available. But I'll grant you the shift (obviously only a problem for something like `UINT32_C(0xBEEF0000) << 16`), though I find that code somewhat unlikely to occur naturally. – EOF Feb 18 '16 at 22:22
  • @EOF `UINT32_C()` being wider than `uint32_t` need only be expected on platforms that do not support `uint32_t`. In that case, the code would fail with `(uint32_t)0xBEEF`. So the remaining reason for using `(uint32_t)0xBEEF` vs. `UINT32_C(0xBEEF)` is to insure code fails compilation. Thanks for the challenging comments. – chux - Reinstate Monica Feb 18 '16 at 22:56
  • 1
    @chux: If your codebase is using `UINT32_C()`, it's *probably* also using `uint32_t`, unless it *deliberately* uses `uint_least32_t` to run on some ancient 36-bit word dinosaur. Which would be *weird*, I mean the fixed-width integer types are pretty new, which would indicate somebody wrote new C99-code for some dusty big iron. Oh, well. – EOF Feb 18 '16 at 23:00

2 Answers2

6

You're right, they're not equivalent for the reason you mention. There's no guarantee that uint32_t is an alias for unsigned long. Include the cast in the #defines if necessary.

You should use the parentheses, see comment by @Keith Thompson for a very good reason why; otherwise sizeof won't work.

unwind
  • 391,730
  • 64
  • 469
  • 606
2

The suffix corresponding to uint32_t is not necessarily UL (it's usually U on 32 bit and 64 bit architectures).

Apart from that, a cast might possibly truncate an integer constant that's wider, but its corresponding suffix wouldn't ever cast down, only up.

(See this table for how suffixes work with integer constants in different bases.)

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142