Okay so I am trying to print hexadecimal values of a struct. Now my print function does the following:
int len = sizeof(someStruct);
unsigned char *buffer = (unsigned char*)&someStruct;
int count;
for(count = 0; count < len; count++) {
fprintf(stderr, "%02x ", buffer[count]);
}
fprintf(stderr, "\n");
Here is the definition of the struct:
struct someStruct {
unsigned char a;
short myShort;
} __attribute__((packed)) someStruct;
The length of this struct printed out as expected is (output on console):
sizeof(someStruct): 3 bytes
Issue here is the following that I am encountering. There is a short which I set to a value.
someStruct.myShort = 0x08;
Now this short is 2 bytes long. When it is printed out into the console however, it does not show the most significant 0x00. Here is the output I get,
stderr: 00 08
I would like the following output however (3 bytes long),
stderr: 00 00 08
If I fill the short with a 0xFFFF, then I do get the 2 byte output, however, whenever there is leading 0x00, it does not output the leading 0x00 to console.
Any ideas on what I am doing wrong. Probably something small I would assume I am overlooking.
After you provided more info, your code is OK for me. It prints the output:
00 08 00
First 00 is from unsigned char a; and second bytes 08 00 are from short. They are switched because of platform dependent data storing in memory.
If you want switched bytes of the short you could just show a short:
fprintf(stderr, "%02x %02x", (someStruct.myShort >> 8) & 0xFF, someStruct.myShort & 0xFF)
I don't see a problem with your code. However, I get 08 00, which makes sense on my little-endian Intel machine.
The problem is in the format of the printf
%02x
%02x means that the result will be printed as hex value (x), with a minimum lenght of 2 (2) and filling the spaces with 0 (0)
Try with
fprintf(stderr, "%04x ", buffer[count]);
The width specifier in the format string (2 in your case) refers to the minimum number of characters in the text output, not the number of bytes to print. Try using "%04x " as your format string instead.
As for the digit grouping (00 08 as opposed to 0008): Plain old printf doesn't support that, but POSIX printf does. Info here: Digit grouping in C's printf
Need to take care not to shift in a signed bit should buffer be signed. Use "hh" to only print 1 byte worth of data. "hh" available with C99. See What is the purpose of the h and hh modifiers for printf?
fprintf(stderr, "%02hhx %02hhx", buffer[count] >> 8, buffer[count]);
[Edit OP's latest edit wants to see 3 bytes] This will print all field's contents. Each field is in the endian order of the machine.
size_t len = sizeof(someStruct);
const unsigned char *buffer = (unsigned char*)&someStruct;
size_t count;
for(count = 0; count < len; count++) {
fprintf(stderr, "%02x ", buffer[count]);
}
fprintf(stderr, "\n");
Related
I don't understand the output in the following C code:
#include <stdio.h>
int main()
{
union U
{
int i;
char s[3];
} u;
u.i=0x3132;
printf("%s", u.s);
return 0;
}
Initial memory is 32 bits and is the binary value of 0x3132 which is
0000 0000 0000 0000 0011 0001 0011 0010.
If the last three bytes of 0x3132 are the value of s (without leading zeroes), then s[0]=0011,s[1]=0001,s[2]=0011.
This gives the values of s=0011 0001 0011=787.
Question: Why the output is 21 and not 787?
The value 0x3132 is represented in memory as: 0x32 , 0x31 , 0x0 , 0x0, because the byte order is in little endian.
The printf call prints out the string represented by the member of the union s. The string is printed out byte by byte. First 0x32 and then 0x31 which are the ascii values for the characters: '2' and '1'. Then the printing stops as the third element is the null character: 0x0.
Note that the representation of int is implementation defined and may not consist of 4 bytes and may have padding. Thus the member of the union s may not represent a string, in which case calling printf with the %s specifier will cause undefined behavior.
first see this code sample:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
int main()
{
union{
int32_t i32;
uint32_t u32;
int16_t i16[2];
uint16_t u16[2];
int8_t i8[4];
uint8_t u8[4];
} u;
u.u8[3] = 52;
u.u8[2] = 51;
u.u8[1] = 50;
u.u8[0] = 49;
printf(" %d %d %d %d \n", u.u8[3], u.u8[2], u.u8[1], u.u8[0]); // 52 51 50 49
printf(" %x %x %x %x \n", u.u8[3], u.u8[2], u.u8[1], u.u8[0]); // 34 33 32 31
printf(" 0x%x \n", u.i32); // 0x34333231
return 0;
}
the union here is just to access the memory of u in 6 different ways.
you may use u.i32 to read or write as int32_t or
you may use u.u32 to read or write as uint32_t or
you may use u.i16[0] or u.i16[1] to read or write as int16_t or
you may use u.u16[0] or u.u16[1] to read or write as uint16_t or
or like this to write as uint8_t:
u.u8[3] = 52;
u.u8[2] = 51;
u.u8[1] = 50;
u.u8[0] = 49;
and read like this as int8_t:
printf(" %d %d %d %d \n", u.u8[3], u.u8[2], u.u8[1], u.u8[0]);
then output is:
52 51 50 49
and read as int32_t:
printf(" 0x%x \n", u.i32);
then output is:
0x34333231
so as you see in this sample code union shares one memory place with many names/types.
in your sample code u.i=0x3132; this writes 0x3132 inside u.i memory, and depending on endianness of you system which is little-endian here, then you asked printf("%s", u.s); from compiler, so u.s is array of type char meaning constant pointer to char type, so this printf("%s", u.s); will reads u.s[0] and prints that on the output stdout then reads u.s[1] and prints that on the output stdout and so on ..., until one of this u.s[i] is zero.
this is what your code doing, so if none of u.s[0], u.s[1], u.s[2], u.s[3] not zero, then memory outside of your union will be read until one zero found or system memory fault error happens.
It means that you machine is little-endian, so the bytes are stored in the opposite order, like this:
32 31 00 00
So: s[0] = 0x32, s[1] = 0x31, s[2] = 0x00.
Even if in theory printing an array of chars using "%s" is undefined behaviour, this works, it prints 0x32 (character '2'), 0x31 (character '1') and then it stops a 0x00.
if you write your code like this:
#include <stdio.h>
int main( void )
{
union U
{
int i;
char s[3];
} u;
u.i=0x3132;
printf("%s", u.s);
printf( "%8x\n", (unsigned)u.i);
}
Then you would see that the contents of u.i is 0x0000000000003132, which would actually be stored as: 0x3231000000000000 due to Endianness
and 0x00 is not a printable character, so the output from the second call to printf() is <blank><blank><blank><blank><blank><blank>3132 as you would expect
and the ascii char 1 is 0x31 and ascii char 2 is 0x32 and the first 0x00 stops the %s operations, so the first printf() outputs 21.
I am encountering a curious issue with sprintf on an embedded system (Libelium Waspmote, similar to Arduino) where sprintf is outputting more characters than given by the format specifier. In this particular instance I am using %02X to output the hexadecimal value of bytes in an array. However on some bytes, instead of writing 2 characters, 4 are being written, with FF being prefixed before the actual byte value. snprintf behaves similarly, except that it respects the buffer size specified and just prints the prefix.
For reference, here is the code snippet printing the array contents:
char *pduChars = (char *) malloc(17*sizeof(char));
pduData.toChar(pduChars);
for (int i = 0; i < 17; i++) {
char asciiCharsS[5];
char asciiCharsSN[3];
int printedS = sprintf(asciiCharsS, "%02X", pduChars[i]);
int printedSN = snprintf(asciiCharsSN, 3, "%02X", pduChars[i]);
USB.print(printedS);
USB.print(" ");
USB.print(printedSN);
USB.print(" ");
USB.print(asciiCharsS);
USB.print(" ");
USB.print(asciiCharsSN);
USB.println(" ");
}
And the output from that snippet (abridged to only the erroneous bytes):
The actual byte sequence should be 0x00 0xFC 0xFF 0xFF 0x48 0xA5 0x33 0x51
sprintf snprintf sprintf Buffer snprintf Buffer
…
2 2 00 00
4 4 FFFC FF
4 4 FFFF FF
4 4 FFFF FF
2 2 48 48
4 4 FFA5 FF
2 2 33 33
2 2 51 51
Am I overlooking something here or might this be a platform-specific issue relating to the implementation of s(n)printf?
I'm guessing your implementation is using signed chars. The format "%X" expects unsigned values. Cast or use unsigned char instead.
/* cast */
int printedS = sprintf(asciiCharsS, "%02X", (unsigned char)pduChars[i]);
int printedSN = snprintf(asciiCharsSN, 3, "%02X", (unsigned char)pduChars[i]);
or
/* use unsigned char */
unsigned char *pduChars = malloc(17); /* cast is, at best, redundant */
/* sizeof (char) is, by definition, 1 */
The format specifier modifiers you are using are only used for padding. In case the value's number of symbols exceeds the specified value, the whole string will be printed.
%02X is for padding... it will not omit...
so in case your value is greater than specified value then whole string will be printed
I have a written a code to convert a large number based on the use input to hexadecimal number. However when the result is printed, the only part of the number is converted to hexadecimal and there are other random values in the array.
for example:
decimal = 1234567891012 ---- the hexa would = 00 00 00 02 00 00 00 65 00 6b 42 48 71 fb 08 44
the last four vales (71 FB 08 44) are the correct hexadecimal value, but the others are incorrect
i am using uint8_t buf[];
Code:
int main()
{
uint8_t buf[] = {0};
long int i,a;
printf("Enter Number: ");
scanf("%d", &buf);
printf("\n");
printf("Input #: ");
/* put a test vector */
for (i = 15; i >= 0; i--)
{
printf("%02x ", buf[i]);
}
printf("\n\n");
printf("\n\n");
printf("%d\n",sizeof(buf));
system("pause");
return 0;
}
Disclaimer: since you've not provided the source code, I shall assume a few things:
this happens because you've used unsigned int to store the decimal, which is 32 bit only on your computer. Use a unsigned long to store a decimal that big.
unsigned long decimal = 12345678901012L;
And for 16 byte decimal, use GMP Lib.
--- edit ---
You must use scanf("%lu", &decimal) to store into a long decimal. The scanf("%d", &decimal) only copies "integer(signed)" which probably is 32 bit on your machine!
After you posted code the problems become more apparent:
First this:
uint8_t buf[] = {0};
Is no good. You need to assign a size to your array, (or make it dynamic), that's why you're getting "garbage" when you go to access the elements. For now, we can just give it an arbitrary size:
uint8_t buf[100] = {0};
That fixes the "garbage" values problem.
Second problem is your scan if is expecting a normal int sized value: "%d" you need to tell it a to look for a bigger values, something like:
scanf("%llu", &buf[0]);
Still, you should validate your input against the limits. Make sure what the user inputs is in the range of LONG_MAX or INT_MAX or whatever type you have.
I am trying to printout an unsigned char value as a 2-Digit hex value, but always getting the result as 4-Digit hex values, not sure what's wrong with my code.
// unsigned char declaration
unsigned char status = 0x00;
// printing out the value
printf("status = (0x%02X)\n\r", (status |= 0xC0));
I am expecting a 2 digit hex result as 0xC0, but I always get 0xC0FF.
As well, when I tried to print the same variable (status) as an unsigned char with the %bu format identifier I got the output as 255.
How do you get just the two hex characters as output?
As far as I know, the Keil C compiler doesn't fully conform to the C standard. If so, it's likely that it doesn't quite follow the standard promotion rules for things like passing char values to variadic functions; on an 8-bit CPU, there are performance advantages in not automatically expanding 8-bit values to 16 bits or more.
As a workaround, you can explicitly truncate the high-order bits before passing the argument to printf. Try this:
#include <stdio.h>
int main(void) {
unsigned char status = 0x00;
status |= 0xC0;
printf("status = 0x%02X\n", (unsigned int)(status & 0xFF));
return 0;
}
Doing a bitwise "and" with 0xFF clears all but the bottom 8 bits; casting to unsigned int shouldn't be necessary, but it guarantees that the argument is actually of the type expected by printf with a "%02X" format.
You should also consult your implementation's documentation regarding any non-standard behavior for type promotions and printf.
you are sending a char to a format string which expects an int. The printf function is grabbing another byte off the stack to fill it out. Try
printf("%02X",(int)(status|0xC0));
Looking at all the answers, I think probably we are missing another way of doing this.
const unsigned char chararr[]="abceXYZ";
for (int i=0; i< 7; ++i) {
printf("%#04X %d %c\n", chararr[i], chararr[i], chararr[i]);
}
0X61 97 a
0X62 98 b
0X63 99 c
0X65 101 e
0X58 88 X
0X59 89 Y
0X5A 90 Z
If you use %#04x small x then the output will b 0x small x prefix. The # pound sign tells the function to print the 0x. 04 to instruct how many digits to output, if input is '0x0a' it will print this,without 04 it will print '0xa'.
In my computer, Dell workstation, the output is as expected by the question. Unless
unsigned char status = 0x00;
printf("status = (0x%02X)\n\r", (status |= 0xC0));
// output
//status = (0xC0)
// is exactly expected by the original question.
Better illustrated by examples:
37 printf("status = (%#02x)\n", (status |= 0xC0));
38 printf("status = (%#04x)\n", (status |= 0xC0));
39 printf("status = (%#04x)\n", 0x0f);
40 printf("status = (%#02x)\n", 0x0f);
status = (0xc0)
status = (0xc0)
status = (0x0f)
status = (0xf)
Cast it to unsigned char:
printf("status = (0x%02X)\n\r", (unsigned char)(status |= 0xC0));
Here is my code which is doing the conversion from hex to decimal. The hex values are stored in a unsigned char array:
int liIndex ;
long hexToDec ;
unsigned char length[4];
for (liIndex = 0; liIndex < 4 ; liIndex++)
{
length[liIndex]= (unsigned char) *content;
printf("\n Hex value is %.2x", length[liIndex]);
content++;
}
hexToDec = strtol(length, NULL, 16);
Each array element contains 1 byte of information and I have read 4 bytes. When I execute it, here is the output that I get :
Hex value is 00
Hex value is 00
Hex value is 00
Hex value is 01
Chunk length is 0
Can any one please help me understand the error here. Th decimal value should have come out as 1 instead of 0.
Regards,
darkie
My guess from your use of %x is that content is encoding your hexademical number as an array of integers, and not an array of characters. That is, are you representing a 0 digit in content as '\0', or '0'?
strtol only works in the latter case. If content is indeed an array of integers, the following code should do the trick:
hexToDec = 0;
int place = 1;
for(int i=3; i>=0; --i)
{
hexToDec += place * (unsigned int)*(content+i);
place *= 16;
}
content += 4;
strtol is expecting a zero-terminated string. length[0] == '\0', and thus strtol stops processing right there. It converts things like "0A21", not things like {0,0,0,1} like you have.
What are the contents of content and what are you trying to do, exactly? What you've built seems strange to me on a number of counts.