unsigned int is not uint32_t when compile to cortex-m0 -- possible C compiler flag issue
Asked Answered
Q

1

5

I've needed to port a project to run with Eclipse with its own Makefile. I have modified its makefile, and i guess the error is connected to it or a compiler flag.

Host: Virtualbox Win 8,x64, target device: nrf51822 which is arm cortex-m0. I use gnu arm cross compiler 4.8.4 (GNU Tools ARM Embedded)

Compile shows the following error/warning message:

src/main.c:173:4: error: format '%u' expects argument of type 'unsigned int', but argument 3 has type 'uint32_t' [-Werror=format=]

I don't understand it. uint32_t is unsigned int in this case. I've included stdint.h.

I compile sources with the following flags:

CFLAGS += -mcpu=cortex-m0 -mthumb -mabi=aapcs --std=gnu11 -funsigned-char -DNRF51 -DDEBUG_NRF_USER -DBLE_STACK_SUPPORT_REQD -DBOARD_PCA10000 -DNRF51822_QFAA_CA
CFLAGS += -Wall -Werror
CFLAGS += -mfloat-abi=soft

Does not -mcpu=cortex-m0 specifies the size of the integer? stdint.h pre-processor macros should generate "typedef unsigned int __uint32_t;". Eclipse shows it that this line is compiled, but i do not know wether to trust it because external makefile is used with its own compiler.

Quaver answered 25/8, 2014 at 21:54 Comment(9)
I'm not sure about this, but I think it's undefined to use %u for uint32_t, even if it has the same size as unsigned int. So the warning might be justified somehow (although it may be safe to ignore it).Lionhearted
Suggest "%" PRIu32 instead of "%u".Zygospore
@Lionhearted No, that's not it, because a) that's not undefined and b) typedefs are just aliases, so if uint32_t really is typedefed as unsigned int then they are exactly the same type. I suspect that the OP is mistaken and unsigned int isn't 32 bits. Printing sizeof(unsigned int) would confirm.Contestation
@Jim Balter Printing sizeof(unsigned int) * CHAR_BIT would confirm even more.Zygospore
Posting code main.c:173 may help.Zygospore
@JimBalter: Ad a) Do you have a source for that? sizeof(uint32_t) == sizeof(unsigned) doesn't imply that they are aliases, they both could be typedefs to some built-in type, as I read the standard, and they both could be different types (similar to how char may be like signed char but a different type). I'm curious if such a warning would be justified even on systems with sizeof(uint32_t) == sizeof(unsigned int)...Lionhearted
@Lionhearted No, I had it mixed up with the fact that you can pass a positive int to %u , but that's because int and unsigned int are "corresponding types". The standard does indeed allow multiple integer types of the same size that aren't compatible, although I don't think there is any such thing in existence and it seems like a bad idea. "similar to how char may be like signed char but a different type" -- but the standard says "The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char" so passing any of them to %c is safe.Contestation
I have managed to run code: int k = sizeof(int); //is 4 k = sizeof(unsigned int); //is 4 k = sizeof(uint32_t); //is 4 k = sizeof(long int);//is 4 k = sizeof(short int);//is 2Quaver
I have a couple of warning like the posted one, but the code is the following: sprintf(buf,"Error: %u %u %s\n\r",error_code, line_num,p_file_name); //which are uint32_t, uint32_t and const uint8_t *Quaver
M
12

uint32_t is a typedef (an alias) for some predefined unsigned integer type. That type is guaranteed to be exactly 32 bits wide, with no padding bits. You cannot safely assume that it's an alias for any particular type. It could plausibly be either unsigned int or unsigned long int. (Less plausibly, it could be unsigned char or unsigned short on an unusual system, or it could be an extended integer type; it cannot be unsigned long long, which is at least 64 bits wide.)

If your implementation has more than one 32-bit unsigned integer type with no padding bits, uint32_t could be any of them, at the whim of the implementer.

Printing a uint32_t value with "%u" is non-portable. You can get away with it if your implementation happens to define uint32_t as unsigned int (yours apparently does not). You can probably get away with it if unsigned int happens to be 32 bits.

The correct format for uint32_t is defined as a macro in <inttypes.h>:

uint32_t x = 42;
printf("x = %" PRIu32 "\n", x);

(PRIu32 expands to a string literal; this takes advantage of the fact that adjacent string literals are concatenated.)

An easier way is to convert the value to a known type:

uint32_t x = 42;
printf("x = %ju\n", (intmax_t)x);

or perhaps:

uint32_t x = 42;
printf("x = %llu\n", (unsigned long long)x);
Mainsheet answered 25/8, 2014 at 23:33 Comment(3)
I see what you mean. Actually i have managed to find that in _default_types.h (included from stdint.h) typedef UINT32_TYPE __uint32_t; and it looks like that this macro is set by the compiler.Quaver
How PRIu32 can be used? Compiler tells for: printf("x = %" PRIu32 "\n", (uint32_t)3); src/main.c:174:19: error: expected ')' before 'PRIu32'Quaver
@Dati: You need #include <inttypes.h>Mainsheet

© 2022 - 2024 — McMap. All rights reserved.