1

First of all, context: I'm implementing a program in ARM Cortex A9 processor. I had an issue related to the C code itself which was solved here: How to set the values of an array to a single variable

First I wrote the code in my computer (OS Linux 64 bits) and the accepted answer in the above link works. However, when I did the same in the ARM A9 it didn't. I did a simple test on ARM:

uint64_t test = 0x1B26B354A1CF;
printf("%lx", test);

it prints:

d

The same in my computer:

 uint64_t test = 0x1B26B354A1CF;
 printf("%lx \n", test);

prints:

1b26b354a1cf

So it seems like an overflow problem or a problem handling that "big" data. How can I find a workaround or an alternative solution to this?

Target: ARTY Z7 FPGA (in this problem you can ignore the "FPGA" part. I'm just workint with the processor this board has: ARM A9 CORTEX)

Miguel Duran Diaz
  • 302
  • 1
  • 3
  • 12
  • Are you using newlib? Are you targeting embedded devices or fill linux? what is `xil_printf`? – KamilCuk Jun 16 '19 at 16:31
  • @KamilCuk Not I'm not using newlib. Added the "target device" on the post. To be honest, I don't know what is xil_printf, since I couldn't find documentation. But it was used among all the tutorials and works I saw using the same board I'm using now. I changed it to printf to avoid confusion. The only thing I found was "printf is buffered and xil_printf isn't buffered". – Miguel Duran Diaz Jun 16 '19 at 16:37
  • 1
    Check if your library printf supports 64 bits number printing. Many do not. – 0___________ Jun 16 '19 at 17:36

3 Answers3

4

You have two problems in your code:

  1. You don't know which suffix to use to define an uint64_t literal on your target platform.

  2. You don't know which format specifier to use in printf for uint64_t values on your target platform.

Both can be solved by using macros defined in stdint.h.

In particular, to define a literal and assign it to a variable:

uint64_t test = UINT64_C(0x1B26B354A1CF);

To print the variable's hexadecimal value in printf:

printf("%" PRIx64 "\n", test);

This is guaranteed to work on any platform that properly supports uint64_t, no matter how many bits its processor is.

While the language itself does not require you to use a suffix for integer literals in most cases - a notable exception is using a literal directly as an argument for a variadic function like printf - doing it explicitly is a good practice in general and may be mandatory in code guidelines of safety-critical projects. For example, the Rule 10.6 of MISRA C:2004 guidelines requires the use of U suffix for all unsigned constants.

Kit.
  • 2,386
  • 1
  • 12
  • 14
  • I read the page, but couldn't figure out how I should use them. There I saw the data types (which I'm already using with uint64_t) and the maximum values of each. Can you elaborate on how to use them? – Miguel Duran Diaz Jun 16 '19 at 17:22
  • 1
    C automatically selects a sufficiently wide type for constants. The lack of a suffix is not a problem in this case. – Eric Postpischil Jun 16 '19 at 17:36
1

For normal printf (and family) the format to print a unsigned long long (which uint64_t most likely is) in hexadecimal is "%llx". Note the extra l size prefix.

Mismatching format specifier and argument type leads to undefined behavior.

What is most likely happening is that long is 32 bits on your 32-bit system, and 64-bits on your home system, that's why it seems to work on your home system.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • You're right. I just tested it. So I shouldn't have problems using 64 bits data in 32 bits system right? Because I had undefined behavior with another part of my code but maybe it's another problem of how I'm handling the data. – Miguel Duran Diaz Jun 16 '19 at 16:44
  • @MiguelDuranDiaz No there's shouldn't be any problems of using 64-bit datatypes on a 32-bit system. – Some programmer dude Jun 16 '19 at 16:45
  • 2
    The proper way to print a `uint64_t` is not to guess that `%llx` might work but to include `` and use `”%” PRIx64`, as in `printf("%” PRIx64 “\n", test);` – Eric Postpischil Jun 16 '19 at 17:33
  • @EricPostpischil Which is why I upvoted the answer by Kit. I'll keep this as it explains what happened. – Some programmer dude Jun 16 '19 at 17:39
0

With regard to the suffix for defining the unsigned 64-bit literal, you can check what suffix is used in your stdint.h for #define UINT64_MAX. In my case, a macro called __UINT64_C(c) is used to paste the suffix UL after the literal if my word size is 64, or ULL if my word size is 32.

gdea73
  • 36
  • 5
  • `__UINT64_C` is not portable. The standard C header defines `UINT64_C` (if the implementation supports `uint64_t`), so that is generally preferred. However, a suffix is not needed when simply assigning a constant to an integer object. C will automatically select a sufficiently wide type for the constant. An explicit type is only needed if the value is being used in a context where the type matters (for example, in a shift expression). – Eric Postpischil Jun 16 '19 at 17:38
  • I figured it the macro was specific to my platform, but I didn't realize there was a standard counterpart. That is good to know. I'm not sure why `__UINT64_C` was not merely defined as `UINT64_C` in my header, given that they are defined identically. – gdea73 Jun 16 '19 at 17:42