For example this code is broken (I've just fixed it in actual code..).
uint64_t a = 1 << 60
It can be fixed as,
uint64_t a = (uint64_t)1 << 60
but then this passed my brain.
uint64_t a = UINT64_C(1) << 60
I know that UINT64_C(1) is a macro that expands usually as 1ul in 64-bit systems, but then what makes it different than just doing a type cast?
(uint64_t)1is formally anintvalue1casted touint64_t, whereas1ulis a constant1of typeunsigned longwhich is probably the same asuint64_ton a 64-bit system. As you are dealing with constants, all calculations will be done by the compiler and the result is the same.The macro is a portable way to specify the correct suffix for a constant (literal) of type
uint64_t. The suffix appended by the macro (ul, system specific) can be used for literal constants only.The cast
(uint64_t)can be used for both constant and variable values. With a constant, it will have the same effect as the suffix or suffix-adding macro, whereas with a variable of a different type it may perform a truncation or extension of the value (e.g., fill the higher bits with 0 when changing from 32 bits to 64 bits).Whether to use
UINT64_C(1)or(uint64_t)1is a matter of taste. The macro makes it a bit more clear that you are dealing with a constant.As mentioned in a comment,
1ulis auint32_t, not auint64_ton windows system. I expect that the macroUINT64_Cwill append the platform-specific suffix corresponding touint64_t, so it might appenduLLin this case. See also https://stackoverflow.com/a/52490273/10622916.