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)

3
  • Are you using newlib? Are you targeting embedded devices or fill linux? what is xil_printf? Commented Jun 16, 2019 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". Commented Jun 16, 2019 at 16:37
  • 1
    Check if your library printf supports 64 bits number printing. Many do not. Commented Jun 16, 2019 at 17:36

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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?
C automatically selects a sufficiently wide type for constants. The lack of a suffix is not a problem in this case.
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.

4 Comments

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.
@MiguelDuranDiaz No there's shouldn't be any problems of using 64-bit datatypes on a 32-bit system.
The proper way to print a uint64_t is not to guess that %llx might work but to include <inttypes.h> and use ”%” PRIx64, as in printf("%” PRIx64 “\n", test);
@EricPostpischil Which is why I upvoted the answer by Kit. I'll keep this as it explains what happened.
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.

2 Comments

__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).
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.