1

I'm using large hexadecimal numbers in my programs and often waste time figuring out how many places the number is.

I know for base-10 numbers an easy way to grasp the size of the number is the multiply-by-1000 method:

// 15mhz clock
uint64_t clk_spd = 15 * 1000 * 1000;

But is there an easy separation method for hexadecimals? My question is effectively, instead of this:

// control register address
uint64_t reg_ctl_addr = 0x2400000000

Can I do something like this:

// control register address
uint64_t reg_ctl_addr = 0x24_0000_0000

I've tried underscores, commas, spaces, even /**/ between the groups of 0s, and nothing compiled.


Edit: I found this related question which is about decimal numbers, but it didn't compile for me:

 % gcc numbers.c                                                                
numbers.c:6:16: error: expected ';' at end of declaration
long m = 24##0000UL;
           ^
           ;
1 error generated.
alk
  • 69,737
  • 10
  • 105
  • 255
Jeeter
  • 5,887
  • 6
  • 44
  • 67
  • If you don't need to use a "standard" environment, you might use [some custom preprocessing](https://stackoverflow.com/questions/3545875/custom-gcc-preprocessor) before passing the program to the compiler. You might for example use `sed` to remove all "°" characters from the program and write the number as `0x24°0000°0000` or you may write a decimal number as `24°000°000`. – Martin Rosenau Dec 06 '19 at 06:17
  • 1
    Do not change your question after comments/answers have been given, as this might render the latter ununderstandable. I rolled back your last change though ... – alk Dec 06 '19 at 06:26
  • 1
    Well, C++ (not C) since the C++14 standard allows to write `24'000'000` too. – trolley813 Dec 06 '19 at 06:30

3 Answers3

3

We can extend the multiply-by-1000 rule to base 16.

A "major jump", for lack of a better term, in base-10 is 1000. GHz = 1000*MHz, etc. In base-16, a major jump is 4 digit places over (not 4 left-shifts). 0x1 -> 0x10000.

So, since we want 4 place shifts, and 1 place shift is a multiply by 16, we just need to multiply by 16^4

Our code becomes:

// control register address
uint64_t ctl_reg_addr = 0x24ull * 0x10000 * 0x10000;

Important to note here from @chux: we need to write 0x24ull because of this caveat of how C typing works. Basically if we just used 0x24 it would be treated as a standard int and the resulting multiplication would overflow

Jeeter
  • 5,887
  • 6
  • 44
  • 67
1
long m = 24##0000UL;

[...] but it didn't compile for me

## is not C but used by the preprocessor only.

So you could do:

#define MY_LARGE_HEX_NUMBER 0x24 ## 0000 ## 0000 ## ULL

...

uint64_t ctl_reg_addr = MY_LARGE_HEX_NUMBER;

which after preprocessing but before compilation would become:

uint64_t ctl_reg_addr = 0x2400000000ULL
alk
  • 69,737
  • 10
  • 105
  • 255
0

What I would recommend is this method:

  • When you type the number out the first time, type 0x24 00 00 00 00.
  • Place that part in a comment. \\ 0x24 00 00 00 00
  • Copy/paste the number and write the declaration:
    uint64_t reg_ctl_addr = 0x24 00 00 00 00; \\ 0x24 00 00 00 00
  • Remove spaces: uint64_t reg_ctl_addr = 0x2400000000; \\ 0x24 00 00 00 00

I also strongly recommend to add u suffix to all hex constants and ll suffix to 64 bit constants. That is: ull.


An alternative method for writing this as an integer constant expressions in a readable way is obviously bit shifts:

uint64_t reg_ctl_addr = 0x24ull << 32;
Lundin
  • 195,001
  • 40
  • 254
  • 396