Why sprintf() generates the question mark character, as output? - c

While working on an embedded project, I noticed that sprintf() method for the following code:
char ln2[16];
sprintf(ln2, "%f Volt", Data[Position].Voltage1);
generates the question mark character as output.
The output generated from the code above is:
? Volt
while the input is declared as double Voltage1 = 0.0;
The same issue does not seem to apply while trying to format an integer.
The following works as expected:
char ln1[16];
sprintf(ln1, "POSITION %d", (Position + 1));
and outputs POSITION 3 where the Position is a global variable and declared as int.
The structure that actually holds the data is:
struct data
{
int Position;
double Voltage1;
double Voltage2;
};
All above while using the C/C++
and the Platform.io extensions both for VS Code.
What is going on wrong here?

Embedded versions of the printf usually do not implement float number handling. You need to let the linker to link the correct version of the function. For example for ARM gcc it will be -u _printf_float or/and -u _scanf_float

ln2 points to a string literal. String literals are read-only, so when you attempt to write to it you invoke undefined behavior.
You should instead define ln2 as a character array which is writable.
char ln2[16];

Related

Is it possible to format strings in C like Python's f-strings?

In Python it's possible to format strings conveniently using f-strings:
num = 12
print(f"num is {num}") # prints "num is 12"
Is it possible to do something like this in C? Or something that is similar to that?
Currently, to add variables to the output I am using this method:
int num = 12;
printf("num is %d", num);
Is this the only way to add variables to a print statment in C?
{num}")
Is it possible to do something like this in C?
No, it is not possible. C language is a programming language without reflection. It is not possible to find a variable by its name stored in a string in C.
Python on the other hand is an interpreted language with a whole interpreter implementation behind it that keeps track of all variable names and values and allows to query it within the interpreted language itself. So in python using a string "num" you can find a variable with that name and query its value.
PS. It is possible with many macros and C11 _Generic feature to omit having to specify %d printf format specifier and get C more to C++-ish std::cout << function overloading - for that, you may want to explore my try at it with YIO library. However, for that, it would be advisable to just move to C++ or Rust or other more feature-full programming language.
As ForceBru said you can use sprintf(char *str, const char *format, ...), but you need to have an alocated string to receive that result:
int num =0;
char output_string[50];
sprintf(output_string,"num is %d", num);
now output_string can be printed as you want

Printing out values of a struct byte by byte

Basically, I'm trying to cast a char array to a pointer to a struct and print out the values in the struct byte by byte. This is because some legacy code I'm dealing with uses a macro to do some bitwise shifting and masking to change 4 bits within an integer in a struct, and I'm trying to find out whether the macro is working as intended. However, I've compressed my problem to this toy example-
#include <stdio.h>
#include <stdint.h>
int main()
{
struct student
{
int32_t hi;
int8_t test
};
struct student p1 = {20, 20};
for(int i = 0; i < sizeof(p1); i++)
{
printf("%c",((char*)&p1)[i]);
}
return 0;
}
For some reason, this prints out two characters (that show up as boxes with 0014 in them) and nothing else. If I change the for loop to go from 0 to 5 (which is roughly the bounds of the for loop that I'm expecting) I get the exact same output. Is there a way to do what I want (i.e. get this to print out 5 characters)? I know that some of the characters will just be empty spaces, but I don't understand how I'm not getting said empty spaces.
You're trying to print binary values as characters. How those characters get printed depends on your console, but byte values of 0 typically don't print anything.
If you want to see what the values of the bytes are, print them as hex numbers instead:
printf("%02x ",((char*)&p1)[i]);
Read more about ASCII. Some characters are control characters so are not shown nicely, and your system might have some weird character encoding. Be aware than in 2019, UTF-8 is used everywhere (almost).
You'll better print your bytes in hexadecimal:
printf("%02x",(unsigned int) ((char*)&p1)[i]);
and you might have an implementation with signed char -s, so it could be better to replace char* with an explicit unsigned char* (or even better uint8_t* from <stdint.h>). Notice that it is documented that printf with %02x wants an unsigned integer (not simply a char). Anything else could be undefined behavior.
Refer at least to some C reference site, and consider looking into the C11 standard n1570.
Of course, enable all warnings and debug info in your compiler (with GCC, compile with gcc -Wall -Wextra -g) and use the debugger (e.g. use gdb). So read How to debug small programs.

printing the hex values after storing it to an array using C

I have done the reading from a file and is stored as hex values(say the first value be D4 C3). This is then stored to a buffer of char datatype. But whenever i print the buffer i am getting a value likebuff[0]=ffffffD4; buff[1]=ffffffC3 and so on.
How can I store the actual value to the buffer without any added bytes?
Attaching the snippet along with this
ic= (char *)malloc(1);
temp = ic;
int i=0;
char buff[1000];
while ((c = fgetc(pFile)) != EOF)
{
printf("%x",c);
ic++;
buff[i]=c;
i++;
}
printf("\n\nNo. of bytes written: %d", i);
ic = temp;
int k;
printf("\nBuffer value is : ");
for(k=0;k<i;k++)
{
printf("%x",buff[k]);
}
The problem is a combination of two things:
First is that when you pass a smaller type to a variable argument function like printf it's converted to an int, which might include sign extension.
The second is that the format "%x" you are using expects the corresponding argument to be an unsigned int and treat it as such
If you want to print a hexadecimal character, then use the prefix hh, as in "%hhx".
See e.g. this printf (and family) reference for more information.
Finally, if you only want to treat the data you read as binary data, then you should consider using int8_t (or possibly uint8_t) for the buffer. On any platform with 8-bit char they are the same, but gives more information to the reader of the code (saying "this is binary data and not a string").
By default, char is signed on many platforms (standards doesn't dictate its signedness). When passing to variable argument list, standard expansions like char -> int are invoked. If char is unsigned, 0xd3 remains integer 0xd3. If char is signed, 0xd3 becomes 0xffffffd3 (for 32-bit integer) because this is the same integer value -45.
NB if you weren't aware of this, you should recheck the entire program, because such errors are very subtle. I've dealed once with a tool which properly worked only with forced -funsigned-char into make's CFLAGS. OTOH this flag, if available to you, could be a quick-and-dirty solution to this issue (but I suggest avoiding it for any longer appoaching).
The approach I'm constantly using is passing to printf()-like functions a value not c, but 0xff & c, it's visually easy to understand and stable for multiple versions. You can consider using hh modifier (UPD: as #JoachimPileborg have already suggested) but I'm unsure it's supported in all real C flavors, including MS and embedded ones. (MSDN doesn't list it at all.)
You did store the actual values in the buffer without the added bytes. You're just outputting the signed numbers with more digits. It's like you have "-1" in your buffer but you're outputting it as "-01". The value is the same, it's just you're choosing to sign extend it in the output code.

sprintf: printing a percent followed by 0-padded hex

I thought I understand printf, but I guess not. I have:
char sTemp[100];
sprintf(sTemp, "%%%02x", (unsigned)c);
I think that c is an unsigned char and I think a linefeed, but for some reason, what I get coming out is
0x0.000000000000ap-1022
If I make the 'x' in the format string an 'X', then an 'X' appears in the output string.
I completely misinterpreted the results of my experiments in the first version of this answer; apologies all around.
The result of that sprintf() call when c is '\n' is this string:
"%0a"
I believe you are then doing:
printf(sTemp);
Which is the same as:
printf("%0a");
Which is a valid format string for hexadecimal float output. You aren't passing a float variable, however, so printf() pulls whatever happens to be on the stack nearby and uses that as the value to format.
Instead, do:
printf( "%s", sTemp );
and you should see your expected "%0a".
Note that clang, and probably other compilers, give you a warning when you use printf(sTemp):
so.c:9:12: warning: format string is not a string literal (potentially
insecure) [-Wformat-security]
Because of precisely this sort of thing: memory on the stack is accessed that wasn't supposed to be.

integer to string converter(using macros)

I was doing basics of macros. I define a macro as follows:
#define INTTOSTR(int) #int
to convert integer to string.
Does this macro perfectly converts the integer to string? I mean are there some situations where this macro can fail?
Can I use this macro to replace standard library functions like itoa()?
for example:
int main()
{
int a=56;
char ch[]=INTTOSTR(56);
char ch1[10];
itoa(56,ch1,10);
printf("%s %s",ch,ch1);
return 0;
}
The above program works as expected.
Interestingly this macro can even convert float value to string.
for example:
INTTOSTR(53.5);
works nicely.
Till now I was using itoa function for converting int to string in all my projects. Can I replace itoa confidently in all projects. Because I know there is less overhead in using macro than function call.
Macros execute during (before to be exact) compile time, so you can convert a literal number in your sourcecode to a string but not a number stored in a variable
In your example, INTTOSTR(56) uses the stringification operator of the preprocessor which eventually results in "56". If you called it on a variable, you'd get the variable name but not its content.
In C, you can use itoa or if you are desperate and would like to avoid it, use snprintf for instance:
snprintf(my_str, sizeof(int), "%i", my_int);
The problem with your macro is that you are thinking about constants, but of course, your macro will be broken when you need to use a variable holding an integer. Your macro would try to stringify the macro name as opposed to the value it would be holding.
If you are fine with constants, your macro is "good", otherwise it is b0rked.
Your macro does not convert integers to strings, it converts a literal into a string literal, which is something very different.
Literals are any plain numbers or definitions of values in your code. when you do int x = 10; the numeral 10 in an integer literal, while x is a variable and int is the type. const char* ten = "10"; also defines a literal, in this case a string literal, with value "10" and a variable called ten which points to the address where this literal is defined. What your macro actually does is change the way the literal is represented before any actual compilation goes on, from an integer literal into a string literal.
So, the actual change is being done before any compilation, just at source code level. Macros are not functions and cannot inspect memory, and your convertion would not work with variables. If you try:
int x = 10;
const char* ten = INTTOSTR(x);
You would be very puzzled to find that your variable ten would actually hold the value "x". That's because x is treated as a literal, and not as a variable.
If you want to see what's going on, I recommend asking your compiler to stop at preprocessing, and see the output before your code is acutally compiled. You can do this in GCC if you pass the -E flag.
PS. Regarding the apparent "success" with conversion of float values, it just comes to show the danger of macros: they are not type-safe. It does not look at 53.5 as a float, but as a token represented by characters 5, 3, . and 5 in the source code.

Resources