How to print 1 byte with printf? - c

I know that when using %x with printf() we are printing 4 bytes (an int in hexadecimal) from the stack. But I would like to print only 1 byte. Is there a way to do this ?

Assumption:You want to print the value of a variable of 1 byte width, i.e., char.
In case you have a char variable say, char x = 0; and want to print the value, use %hhx format specifier with printf().
Something like
printf("%hhx", x);
Otherwise, due to default argument promotion, a statement like
printf("%x", x);
would also be correct, as printf() will not read the sizeof(unsigned int) from stack, the value of x will be read based on it's type and the it will be promoted to the required type, anyway.

You need to be careful how you do this to avoid any undefined behaviour.
The C standard allows you to cast the int to an unsigned char then print the byte you want using pointer arithmetic:
int main()
{
int foo = 2;
unsigned char* p = (unsigned char*)&foo;
printf("%x", p[0]); // outputs the first byte of `foo`
printf("%x", p[1]); // outputs the second byte of `foo`
}
Note that p[0] and p[1] are converted to the wider type (the int), prior to displaying the output.

You can use the following solution to print one byte with printf:
unsigned char c = 255;
printf("Unsigned char: %hhu\n", c);

If you want to print a single byte that is present in a larger value type, you can mask and/or shift out the required value (e.g. int x = 0x12345678; x & 0x00FF0000 >> 16). Or just retrieve the required byte by casting the needed byte location using a (unsigned) char pointer and using an offset.

Related

Converting unsigned char array to signed short in C

I want to convert an array of unsigned char to a signed int!
I've already done some try, and the conversion works for the single element like this:
unsigned char byte[2];
signed char *valueS[2];
byte[0] = 0b11110111;
byte[1] = 0b00001001;
//Conversion
for(int i = 0; i < 2; i++)
{
valueS[i] = (signed char*)&byte[i];
}
//Result
printf("Val 0 -> %d \n", *valueS[0]); // print -9 Correctly
printf("Val 1 -> %d \n", *valueS[1]); // print 9 Correctly
//But when i try to print a 16 bit signed
printf("Int %d \n", *(signed short*)valueS); //It doesn't work! I expected -2295
How can i get the 16 bit signed int from that unsigned char array? Thank you in advance!
How can i get the 16 bit signed int from that unsigned char array?
Supposing you mean you want to obtain the int16_t whose representation is byte-for-byte identical to the contents of an arbitrary array of two unsigned char, the only conforming approach is to declare an int16_t object and copy the array elements to its representation. You could use the memcpy() function to do the copying, or you could do it manually.
For example,
#include <stdint.h>
// ...
unsigned char byte[2] = { 0xF7, 0x05 };
int16_t my_int;
unsigned char *ip = (unsigned char *) &my_int;
ip[0] = byte[0];
ip[1] = byte[1];
printf("Int %d \n", my_int);
You might see a recommendation to use a pointer aliasing trick to try to reinterpret the bytes of the array directly as the representation of an integer. That would take a form similar to your code example, but such an approach is non-conforming, and formally it yields undefined behavior. You may access the representation of an object of any type via a pointer to [unsigned] char, as the code in this answer does, but, generally, you may not otherwise access an object via a pointer to a type incompatible with that object's.
Note also that the printf above is a bit sloppy. In the event that int16_t is a different type from int, such as short int, the corresponding printf directive for it will have a length modifier in it -- likely %hd. But because of details of the way printf is declared, it is the result of promoting my_int to int that will be passed to printf. That rescues the mismatch, and in practice, the printed result will be the same as if you used the correct directive.

Printing the hex value stored as a string gives unexpected output

I have in C language hex numbers defined in string:
char chars[] = "\xfb\x54\x9c\xb2\x10\xef\x89\x51\x2f\x0b\xea\xbb\x1d\xaf\xad\xf8";
Then I want to compare the values with another. It is not working and if I print the value like:
printf("%02x\n", chars[0]);
it writes fffffffb. Why is that and how to get fb value exactly?
This is because of the sign extension.
Change
printf("%02x\n", chars[0]);
to
printf("%02x\n", (unsigned char)chars[0]);
The %x format specifier will read 4 bytes on 32bit machine. As you have declared chars as the character array, when fetching the value fb(negative value) will be sign extended as fffffffb, where the MSB of fb is set to all other bits before it.
Refer this for more details sign extension
If you would have declared char chars[] as unsigned char chars[] then the print would have been as expected.
As per the standard mentioning regarding the %x format specifier with fprintf()
o,u,x,X
The unsigned int argument is converted to unsigned octal (o), unsigned
decimal (u), or unsigned hexadecimal notation (x or X) in the style dddd; [...]
So, the expected type of argument to %x is unsigned int.
Now, printf() being a variadic function, only default promotion rule is applied to its arguments. In your code, chars being an array of type char (signedness of which is implementation dependent), in case of
printf("%02x\n", chars[0]);
the value of chars[0] get promoted to an int which is not the expected type for %x. Hence, the output is wrong, as int and unsigned int are not the same type. [Refer ยง6.7.2, C11]. So, without an explicit cast like
printf("%02x\n", (unsigned int)chars[0]);
it invokes undefined behaviour.
FWIW, if you're having a C99 supported compiler, you can make use of the hh length modifier to work around this, like
printf("%02hhx\n", (unsigned char)chars[0]);
It's because of sign extension.
This will work as you expect:
printf("%02x\n", (unsigned char)chars[0]);

Sign extension query in case of short

Given,
unsigned short y = 0xFFFF;
When I print
printf("%x", y);
I get : 0xFFFF;
But when I print
printf("%x", (signed short)y);
I get : 0xFFFFFFFF
Whole program below:
#include <stdio.h>
int main() {
unsigned short y = 0xFFFF;
unsigned short z = 0x7FFF;
printf("%x %x\n", y,z);
printf("%x %x", (signed short)y, (signed short)z);
return 0;
}
Sign extension happens when we typecast lower to higher byte data type, but here we are typecasting short to signed short.
In both cases sizeof((signed short)y) or sizeof((signed short)z) prints 2 bytes. Short remains of 2 bytes, if sign bit is zero as in case of 0x7fff.
Any help is very much appreciated!
Output of the first printf is as expected. The second printf produces undefined behavior.
In C language when you pass a a value smaller than int as a variadic argument, that value is always implicitly converted to type int. It is not possible to physically pass a short or char variadic argument. That implicit conversion to int is where your "sign extension" takes place.
For this reason, your printf("%x", y); is equivalent to printf("%x", (int) y);. The value that is passed to printf is 0xFFFF of type int. Technically, %x format requires an unsigned int argument, but a non-negative int value is also OK (unless I'm missing some technicality). The output is 0xFFFF.
Conversion to int happens in the second case as well. I.e. your printf("%x", (signed short) y); is equivalent to printf("%x", (int) (signed short) y);. The conversion of 0xFFFF to (signed short) is implementation-defined, because 0xFFFF is apparently out of range of signed short on your platform. But most likely it produces a negative value (-1). When converted to int it produces the same negative value of type int (again, -1 represented as 0xFFFFFFFF for a 32-bit int). The further behavior is undefined, since you are passing a negative int value for format specifier %x, which requires unsigned int argument. It is illegal to use %x with negative int values.
In other words, formally your second printf prints unpredictable garbage. But practically the above explains where that 0xFFFFFFFF came from.
Let's break it down and into smaller pieces:
Given,
unsigned short y = 0xFFFF;
Assuming two-bytes unsigned short maximum value is 2^16-1, that is indeed 0xFFFF.
When I print
printf("%x", y);
Due to default argument promotion (as printf() is variadic function) value of y is implicitly promoted to type int. With %x format-specified it's treated as unsigned int. Assuming common two-complement's representation and four-bytes int type, that means that as most-significant bit is set to zero, the bit patterns of int and unsigned int are simply the same.
But when I print
printf("%x", (signed short)y);
What you have done is cast to signed type, that cannot represent value of 0xFFFF. Such conversion as standard stays is implementation-defined, so you can get whatever result. After implicit conversion to int apparently you have bit-patern of 32-ones, that are represented as 0xFFFFFFFF.

Convert int (32 bits) to char (8 bits)

I have these definitions:
int data = uartBaseAddress[UART_DATA_REGISTER / 4]; // data coming from UART RX port
char message[20]; // array of 20 chars
Now when I try to do this:
message[0] = (char) data;
printf("%x", message[0]);
It prints (for example): "ffffff9c".
Of course I want only the last 8 bits ("9c") and I don't understand how to properly do the conversion from int to char.
EDIT: I mean: i have to populate the array like this:
data = 0xFFFFFF9c;
message[0] = data & 0xFF; -- it has to contain only 9c
data = 0xFFFFFFde;
message[1] = data & 0xFF; -- it has to contain only de
etc...
The conversion is correct. It's the printf that's the problem.
Apparently plain char is signed on your system (it can be either signed or unsigned).
I'm going to guess that the value printed was ffffff9c (8 digits), not ffffffff9c (10 digits); please verify that.
The value of data was probably -100. Converting that value from int to char would yield -100, since that value is within the range of type char (probably -128 .. +127).
But the %x format specifier requires an argument of type unsigned int, not int. The value of message[0] is promoted to int when it's passed to printf, but printf, because of the format string, assumes that the argument is of type unsigned int.
Strictly speaking, the behavior is undefined, but most likely printf will simply take the int value passed to it and treat it as if it were an unsigned int. (int)-100 and (unsigned int)0xffffff9c have the same representation.
There is no printf format specifier to print a signed value in hexadecimal. If you change the format from %x to %d, you'll at least see the correct value.
But you should step back an decide just what you're trying to accomplish. If you want to extract the low-order 8 bits of data, you can do so by masking it, as unwind's answer suggests. Or you can convert it to unsigned char rather than plain char to guarantee that you'll get an unsigned value.
An unsigned char value is still promoted to int when passed to printf, so to be fully correct you should explicitly convert it to unsigned int:
int data = ...;
unsigned char message[20]; // change to unsigned char
message[0] = data; // no cast needed, the value is implicitly converted
printf("%x", (unsigned int)message[0]);
Strictly speaking, the (unsigned int) isn't necessary. message[0] is an unsigned char, so it will be converted to a non-negative int value, and there's a special-case rule that says int and unsigned int arguments with the same value are interchangeable as function arguments. Still, my own preference is to use the cast because it's clearer, and because adding the cast is easier (particularly for anyone reading the code) than following the line of reasoning that says it's not necessary.
There's no need for message, just mask off the bits you don't want:
printf("%x\n", data & 0xff);
To convert a 32-bit integer to a 4-element array of 8-bit numbers, do:
const uint32_t data = ...
uint8_t message[20];
for(int i = 0; i < 4; ++i)
{
message[i] = data & 0xff;
data >>= 8;
}
The above uses little-endian byte order. If data is 0x12345678, then message will begin 0x78, 0x56, 0x34, 0x12.

Printing the memory representation of an integer using char* and unsigned char*

I am stuck with a problem here. I entered an integer, casted the integer pointer and sent it into a function print_bytes which accepts a char* pointer and the number of bytes to be printed. Tried printing the address of each byte and the number in type hexadecimal. But with 250 the o/p should have been fa for the first byte and zeroes for next 3 bytes, but instead it prints fffffffa for the first byte.
#include<stdio.h>
using namespace std;
void print_bytes(char* ptr,int len)
{
for(int i=0;i<len;i++)
{
printf("%p %x\n",ptr+i,*(ptr+i));
}
}
int main()
{
int a=250;
print_bytes((char*)&a,4);
return 0;
}
But when I change the pointer type to unsigned char* it gives the correct output.
That means the MSB being one for char* is making the output go wrong. Or am I missing something?
The type is getting promoted to signed int when passed to the printf function. When a signed type is promoted, it's "sign-extended".
To an 8-bit signed char, the value 250 is equivalent to -6 (2's complement) and since it's signed, -6 is considered the "true" value.
When this is extended to a signed integer (4 bytes), as is happening here, the value -6 is preserved (through the sign-extension), rather than the value 250. But -6 on a 4 byte value is fffffffa, whereas it's merely fa on a single byte.
Since the MSB acts as a flag for the sign, if it's set, you get the behaviour you've observed.
Casting to (unsigned char) on the printf call will cause the value to be "zero-extended" instead. This will cause the value 250 to be preserved, rather than the value -6, and will result in the behaviour you want.
It is a requirement of printf (as set by the standard), being a variadic function (vararg), that arguments narrower than an int be promoted to an int prior to being passed, hence the sign-extension in the first place. (It also requires the promotion of float to double).
printf("%p %02x\n",ptr+i,(unsigned char)*(ptr+i));
This is because (on your system) char is signed, and it's getting promoted to int in the printf() call.
Use unsigned char:
void print_bytes(const unsigned char *ptr, size_t len)
{
for(size_t i = 0; i < len; ++i)
{
printf("%p %x\n", ptr + i, ptr[i]);
}
}

Resources