C sprintf breaks with byte parameters (Keil compiler) - c

I have code running in 2 projects/platforms. It works in one, not the other. Code is like this:
uint8_t val = 1;
uint8_t buff[16];
sprintf(buff, "%u", val);
The expected output is "1" (gcc) but on one compiler (Keil) it returns "511", which in hex is 0x1FF. Looks like its not promoting the byte to int with this compiler. This is confirmed because it works ok if I do this:
sprintf(buff, "%u", (int)val);
My question is this: why does one compiler do what I consider the 'right thing', and one does not? Is it my incorrect expectations/assumptions, a compiler setting, or something else?

For maximum portability, you can use these macros from inttypes.h: (there are others)
PRId8, PRIx8, PRIu8
PRId16, PRIx16, PRIu16
PRId32, PRIx32, PRIu32
Normally (as I expected):
#define PRIu8 "u"
But for the Keil compiler in this case:
#define PRIu8 "bu"
e.g.,
printf("0x%"PRIx8" %"PRIu16"\n", byteValue, wordValue);
That's pretty cumbersome though. I suggest more friendly compilers.
It's amazing what you don't know about this stuff even after doing it for decades.

Your assumption may be correct, or incorrect. It depends on the compiler implementation. All modern (or should say smart) compiler will do that like you mentioned. But Keil, as of ver. 9.02, you need to specify correct variable length for printf.
This is Keil C's way handling all kinds of printf functions.
You need to specify exactly how long it is. All regular are for 16-bit (unsigned) integer including %d, %x, and %u. Use modifier 'b' for 8-bit and 'l' for 32-bit. If you gave wrong length, you would get wrong number. Even worse, the rest of the variables are all wrong.
For example, to use 8-bit 'char', you use '%bd' (%bu, and %bx), and %ld, %lu, and %lx for 32-bit 'long'.
char c = 0xab;
printf("My char number is correctly displayed as '0x%02bx'\n", c);
Also note, likewise, to get numeric data from sscanf, it's same. The following example is to get a 32-bit long variable using sscanf:
long var;
char *mynum = "12345678";
sscanf(mynum, "%ld", &var);
Variable var contains number 12345678 after sscanf.
Hereunder shows the length for variables used in printf family for Keil.
%bd, %bx, %bu - should be used for 8-bit variables
%d, %x, %u - should be used for 16-bit variables, and
%ld, %lx, %lu - should be used for 32-bit variables

Related

Problem with using scanf function under stm32

I've came across on some interesting thing during use of sscanf() for STM32F437:
uint8_t var;
st = sscanf(&line[off], "%x", &var);
st = sscanf(&line[off], "%hhx", &var);
When I'm trying to compile first line I get suggestion from gcc to use "%hhx" instead of "%x". But when I changed this line to the second one - suggestion from gcc disappeared, but the result of scanning is wrong.
When &line[off] points to following string: 52 then the first scanf(..."%x"...) is working correctly giving 0x52, but the second scanf(..."%hhx"...) produces result 0x34.
Seems like scanf("..."%hhx"...") interpretes 52 as a decimal value 52 and then converts it to hexadecimal value 0x34.
I am using arm-none-eabi-gcc version 9.2.0.
Did I miss something or this is some bug in scanf()?
You are linking against what is commonly refereed as "newlib-nano". Nano version of newlib comes with limited support from the standard library - it doesn't support all C99 length modifiers, like ll or hh in both printf and scanf.
The solution is to link against full implementation of newlib, so remove -specs=nano.specs or similar from the linking options, or don't use hh length modifier when compiling with newlib-nano or use other method of converting a string to an integer.
%x without a prefix before the x means scanf is expecting a pointer to unsigned int
%hh is used for signed char or unsigned char.
%hhx is used for signed char or unsigned char in hex format.
"%"SCNu8 is used for scanning uint8_t.
"%"SCNx8 is used for uint8_t in hex format.
uint8_t is most likely 100% equivalent to unsigned char on any system.
This means that here "%x", &var you lie to the compiler and (assuming 32 bit CPU) you tell it "go ahead and read 32 bit large integer), then pass a memory address where only 8 bits of valid data are stored. This is undefined behavior and anything can happen.
Speculating about why undefined behavior bugs manifest themselves in a certain way for your specific system is rather meaningless.
Instead, do this:
#include <inttypes.h>
uint8_t var;
st = sscanf(&line[off], "%"SCNx8, &var);
Please note that sscanf is a terribly slow and dangerous function and should not be used on embedded systems. Always use strtoul instead.

Is it valid to use %lu in a format string for printf where PRIu32 would be expected?

Assuming I have, for example, a variable i of type uint32_t. The expected way to print it would be like that:
printf("%"PRIu32"\n", i);
However, it should be noted that it is required for long unsigned int to be at least 32bits wide. The correct specifier for long unsigned int is %lu. Thus, can the above statement be replaced with:
printf("%lu\n", i);
I’d suppose yes, since I can see no reason why not. However, if yes, then this would remove the need for existence of these macroified specifiers like PRIu32, so I figure I’d better ask.
The reason I’m asking it is that I’d like to create a format string for printf dynamically, and it’d be hard to allocate space for this format string if I don't know the size of the string PRIu32 expands to (and whether sizeof(PRIu32) is valid or not may be worthy of a separate question).
In any case, I suppose it should be valid to write:
printf("%lu\n", (long unsigned)i);
Thus, can the above statement be replaced with:
printf("%lu\n", i);
I’d suppose yes, since I can see no reason why not.
No, because long unsigned int can be larger than 32 bits, or if exactly 32-bits can nevertheless have a different representation than does uint32_t.
In any case, I suppose it should be valid to write:
printf("%lu\n", (long unsigned)i);
Yes, and as you observed, it is also safe, because long unsigned int is required to be able to represent all the values that a uint32_t can take.

Displaying an integer to hex in C

I have this part of code in C class:
int i;
for (i=0;i<val;i++)
mdl_print ("%u ", rec->payload[i]);
mdl_print ("\n");
Variable rec->payload is uint8_t type. I would print it in hexadecimal notation.
How can I do? Thanks.
Quick and easy:
print("%x", (int)(rec->payload[i]));
To display in the format 0x05 then use:
print("0x%02x", ...)
instead.
If mdl_print() works like the standard C function printf(), try something like the following:
printf( "%02x", (int) rec->payload[i] );
The basic printf formatting code for writing in hexadecimal is %x. "02" means to pad the number with '0' until it's two characters wide, which is how you'd normally print an int8.
Many custom output functions follow the format of printf in this way, since it's very familiar to C programmers. You can read more about printf on its man page: http://linux.die.net/man/3/printf
Use "%x", so:
mdl_print ("%x ", rec->payload[i]);
This will give you a hex number that is the "length necessary". If you want a fixed length, use "%02x" for two digits padded with zeros.
Note that providing a uint8_t or int where an unsigned int is expected in printf is undefined behaviour, as stated by section 7.21.6.1p9 of n1570.pdf: "If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined." According to 7.21.6.1p8, %x tells printf to expect an unsigned int. Make sure you explicitly cast your uint8_t to (unsigned int), or use the PRIx8 macro found in <stdint.h>.
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
int main(void) {
uint8_t foo = 42;
/* These two printfs are equivalent: */
printf("Hex for %02u: %02x\n", (unsigned int) foo, (unsigned int) foo);
printf("Hex for %02" PRIu8 ": %02" PRIx8 "\n", foo, foo);
return 0;
}
First your title is so wrong... Casting integer to hex in C casting implies a type change, hex is a number system not a type. You're "displaying an integer in hex" not "casting". If you don't understand the difference please ask for clarification.
As far as the displaying goes, it depends what you want the result to look like. One short cut that I typically use is:
mdl_print("%#x ", rec->payload[i]);
Which displays values as:
0xA6
The caveat on this syntax is that it doesn't work with 0, you don't get 0x0 just 0. So an alternative would be:
mdl_print("0x%x ", rec->payload[i]);
Which will display the value as 0xA6 or 0x0 or whatever it maybe. Of course if you don't want the 0x part you can always just do:
mdl_print("%x ", rec->payload[i]);
Your max value (in hex) with a unsigned 8-bit number is 0xFF so if you want them all to display the same "width" you can use the size specifier too:
mdl_print("%02x ", rec->payload[i]); // or mdl_print("0x%02x, rec->payload[i]);
// or whatever you picked

portable way to deal with 64/32 bit time_t

I have some code which is built both on Windows and Linux. Linux at this point is always 32bit but Windows is 32 and 64bit. Windows wants to have time_t be 64 bit and Linux still has it as 32 bit. I'm fine with that, except in some places time_t values are converted to strings. So when time_T is 32 bit it should be done with %d and when it is 64bit with %lld... what is the smart way to do this? Also: any ideas how I may find all places where time_t's are passed to printf-style functions to address this issue?
edit:
I came up with declaring TT_FMT as "%d" or "%lld" and then changing my printfs as in
printf("time: %d, register: blah") to be printf("time: " TT_FMT ", register: blah")
Is there a better way? And how do I find them all?
According to the C standard, time_t is an arithmetic type, "capable of representing times". So, it could be double for example. (Posix mentions this more explicitly, and also guarantees that time() returns the number of seconds since the Epoch—the latter is not guaranteed by the C standard.)
Maybe the cleanest solution is to convert the value to whatever type you want. You may want one of unsigned long long or unsigned long:
printf("%llu\n", (unsigned long long)t);
I think the only truly portable way is to use strftime to convert the time_t to a string.
If you're sure that you're only operating on platforms where time_t is an int, you could cast to intmax_t (from stdint.h) and print it using PRIdMAX (from inttypes.h).
If you want to go with the macro specifier, I would recommend one minor tweak. Instead of encapsulating the entire specifier, encapsulate just the modifier:
#ifdef 64_BIT_TIME
#define TT_MOD "ll"
#else
#define TT_MOD ""
#endif
and then using it like this:
printf("current time in seconds is: %" TT_MOD "u", time(0));
The reason why is that while you primarily want the second in decimal, every so often you may want hex (or perhaps you want leading 0's). By only having the modifier there, you can easily write:
"%" TT_MOD "x" // in hex
"%08" TT_MOD "d" // left pad with 0's so the number is at least 8 digits
Slight adjustment on Alok's answer, it's signed on both Windows and Linux, so:
printf("%lld\n", t);
is cleaner.

printf with sizeof on 32 vs 64 platforms: how do I handle format code in platform independent manner?

I have some code that prints the amount of memory used by the program. The line is similar to this:
printf("The about of RAM used is %u", anIntVariable*sizeof(double) );
where anIntVariable is an int variable for the number of elements of the double array. Anyhow, on 32-bit systems I never had any problems but on 64-bit systems, I get a compiler warning about using "%u" for a unsigned long integer. Using "%lu" as the format code fixes the problem on 64-bit but causes the compiler to complain on 32-bit because the type is back to unsigned int. I've found that, indeed, sizeof(double) returns a different value on 32 vs 64 bit systems. I've found some webpage guides to convert code from 32 bit to 64 bit But I'd rather have code that works on both instead of just converting back and forth.
How do I write this line in a platform independent way? I know many ways I could do it using preprocessor directives but that seems like a hack. Surely there's an elegant way that I'm not realizing.
Portable printf identifiers are provided in the include file inttypes.h or here.
This include file has many portable identifiers for your specific runtime. For your example, you want PRIuPTR, which means "PRintf Identifier unsigned with size of up to a pointer's size".
Your example will then be:
printf("The amount of RAM used is %" PRIuPTR, anIntVariable*sizeof(double) );
Results on 64bit Linux with GCC 4.3 (int anIntVariable = 1):
$ gcc test.c -m32 -o test && ./test
The amount of RAM used is 8
$ gcc test.c -o test && ./test
The amount of RAM used is 8
For completeness sake, there are identifiers for scanf too, whose prefixes are SCN.
The return value of sizeof is a size_t. If you're using a C99 compliant compiler it looks like you can use %zd%zu for this.
D'oh: %zu (unsigned) of course. Thanks, ony.
First of all, you should match the "%" specifier with the actual data type you want to print. sizeof returns the data type size_t, and just as you shouldn't try to print a float using a "%d" specifier, you shouldn't try to print a size_t with "%u" or "%d" or anything that doesn't really mean size_t.
The other replies have given some good ways to handle this with newer compilers ("%z" and PRIu32), but the way we used to do this was simply to cast the size_t to unsigned long, and then print it using "%lu":
printf("The amount of RAM used is %lu", (unsigned long)(anIntVariable*sizeof(double)) );
This will not work on systems where size_t is wider than a long, but I don't know of any such systems, and I'm not even sure if the standard allows it.

Resources