Write hex bytes to file using fwrite (little endian issue) - c

I am trying to write hex bytes to file using fwrite but it's in wrong order due to little endian. Does anyone know an easy way to fix the problem without writing another function to swap the bytes? Thanks.
My code is actually to convert every 8 bytes binary sequence to 2 bytes hexdecimal value and write to the file. For example, 00000000 -> 00 , 00010010 -> 12, ..., and write each 2 byte result to the file.
What I used to write to the file is:
unsigned char hex;
char two_bytes[8]=""; // 8 bytes binary sequence
hex = strtol(two_bytes, NULL, 2);
fwrite(&hex, sizeof(hex), 1, fd); //but write in the wrong order

You can convert from whatever your host endianness is to "network endian" (big endian) with htonl.
hex = htonl(strtol(two_bytes, NULL, 2));
... if you don't mind pulling in some fancy headers.

Related

How to write portable binary files in C?

Let us consider the following pice of code:
#include <stdio.h>
int main(){
int val = 30;
FILE *file;
if(!(fopen("file.bin","wb"))){
fwrite(&val,sizeof(int),1,file);
fclose(file);
}
return 0;
}
I was wondering about what happens if I try to read the file resulting from this code with fread in an architecture where integers have a different size from the integers in the architecture that produced the file. I think that the result will not match the original value of the variable val in this code.
If this is true, how can we deal with this problem? How can we produce portable binary files in C?
I was wondering about what happens if I try to read the file in an architecture where integers have a different size from the integers in the architecture that produced the file.
That is absolutely a good thing to worry about. The other big concern is byte order.
When you say
fwrite(&val, sizeof(int), 1, file);
you are saying, "write this int to the file in binary, using exactly the same representation it has in memory on my machine: same size, same byte order, same everything". And, yes, that means the file format is essentially defined by "the representation it has on my machine", not in any nicely-portable way.
But that's not the only way to write an int to a file in binary. There are lots of other ways, with varying degrees of portability. The way I like to do it is simply:
putc((val >> 8) & 0xff, file); /* MSB */
putc( val & 0xff, file); /* LSB */
For simplicity here I'm assuming that the binary format being written uses two bytes (16 bits) for the on-disk version of the integer, meaning I'm assuming that the int variable val never holds a number bigger than that.
Written that way, the two-byte integer is written in "big endian" order, with the most-significant byte first. If you want to define your binary file format to use "little endian" order instead, the change is almost trivial:
putc( val & 0xff, file); /* LSB */
putc((val >> 8) & 0xff, file); /* MSB */
You would use some similar-looking code, involving calls to getc and some more bit-shifting operations, to read the bytes back in on the other end and recombine them into an integer. Here's the little-endian version:
val = getc(file);
val |= getc(file) << 8;
These examples aren't perfect, and are guaranteed to work properly for all values only if val is an unsigned type. There are more wrinkles we might apply in order to deal with signed integers, and integers of size other than two bytes, but this should get you started.
See also questions 12.42 and 16.7 in the C FAQ list.
See also this chapter of some on-line C Programming notes.

How to properly receive hex data from serial communication in linux

I have been searching for this similar issue on internet but haven't found any good solution. I am in ubuntu and I am receiving serial hex data on serial port. I have connected my system using null modem cable to windows system and windows system is running docklight software which is sending hex data like below:
2E FF AA 4F CC 0D
Now by saving the data, I do not mean that I want to print data on terminal. I just want to save this data as it is in a buffer so that I an later process it.
To read the data I am doing
res = read (fd, buf, sizeof buf)
//where buf is
unsigned char buf[255];
At this point after reading, buf contains some random chars. From some links on internet, I got a way to convert it into hex:
unsinged char hexData[255];
for (int i = 0; i < res; i++)
{
sprintf((char*)hexData+i*2, "%02X", buf[i]);
}
Now this hexData contains 2EFFAA4FCC0D, which is ok for my purpose. (I do not know if it is the right way of doing it or not). Now lets say I want to convert E from the hexData into decimal. But at this point, E will be considered as character not a hex so may be I'll get 69 instead of 14.
How can I save hex data in a variable. Should I save it as array of chars or int. Thanks.
You already have data in binary form in buf
But if you still need to convert hex to decimal, you can use sscanf
sscanf(&hexBuf[i],"%02X",&intVar);// intVar is integer variable
It wll convert hex byte formed by hexBuf[i] and hexBuf[i+1] to binary in intVar, When you printf intVar with %d you will get to see the decimal value
You can store intVar as element of unsigned character array
You may want to think about what you're trying to achieve.
Hexadecimal is just a representation. The byte you are receiving could be shown as hexadecimal pairs, as binary octet or as a series of (more or less) printable characters (what you see if you print your unsigned char array).
If what you need is storing only the hexadecimal representation of those bytes, convert them to hexadecimal as you are doing, but remember you'll need an array twice as big as your buffer (since a single byte will be represented by two hexadecimal characters once you convert it).
Usually, the best thing to do is to keep them as an array of bytes (chars), that is, your buf array, and only convert them when you need to show the hexadecimal representation.

fwrite not behaving as it should be

I have a C program that writes to a file using fwrite(..) and the result is not consistent with the function's arguments I provide.
uint32_t x = 1009716161;
FILE * file = fopen("helloop.txt", "wb+");
rewind(file);
fwrite( &x, sizeof(uint32_t), 1, file);
fclose(file);
When I check the file afterward it seems to contains symbols that does not translate into anything
>cat helloop.txt
>Á/<
as I should be getting this
>cat helloop.txt
>000000003C2F0BC1
I checked the file's permissions and I chmodded it
chmod 777 helloop.txt
The way I see it I have a 1 element of size 32 bit integer that I want to write to file,
what am I doing wrong ?
Your program did exactly what you told it to.
In general, if a program you've written seems to be misbehaving, you shouldn't jump to the conclusion that the operating system, the compiler, or the runtime library is at fault. It's far more likely that there's a bug in your program, or that you've misunderstood something. That remains true no matter how many years of experience you have.
The value 1009716161, expressed in hexadecimal, is 0x3c2f0bc1. When you write that value to a binary file, you write 4 8-bit bytes, with values 0x3c, 0x2f, 0x0b, and 0xc1. In ASCII, those are '<', '/', and two characters outside the printable ASCII range. The order in which they're written depends on the endianness your system, but the contents you report seem consistent with that.
I"m not sure why you'd expect to see 000000003C2F0BC1. That's 16 byte when you only wrote 4 bytes to the file. Furthermore, binary files do not contain an ASCII rendering of the hexadecimal representation of the data you wrote -- they just contain the data.
If you examine the file by converting it from raw binary to hexadecimal (by using the hexdump or od -x command if your system has it), you should see something recognizable.
And if you open the file in binary mode and use fread to read the data back into a uint32_t object, you should get the original value 1009716161 back -- which is the whole point.
cat helloop.txt
Á/<
cat prints character data. It doesn't print a 4-byte value in a file as a 32-bit integer.
as I should be getting this
cat helloop.txt
000000003C2F0BC1
No you shouldn't, not with cat. You'd have to write the character string "000000003C2F0BC1" to the file if you expect to get that. The file would probably be 16 characters long. I'd bet right now if you run ls -l helloop.txt you'll see size 4 because you wrote a uint32_t binary integer to the file.
what am I doing wrong ?
As far as I can tell, the only thing you've done wrong is expecting cat to print out your uint32_t as a hexadecimal representation. (Though I did not check your hex value, so that may be incorrect as well)
See if you have hexdump on your Linux machine, it may give you better results.
EDIT: If you actually DO want to print a uint32_t as a hex string, you can use fprintf(..., "%x", x) with the x or X format specifier, but keep in mind this is not compatible with fwrite/fread, so to read it back in you'll have to read in the string and convert back from hex to int.

Write Hex in C (byte)

I have to write a byte in hex to a file but I have a problem. For example.
If I have:
unsigned char a = 0x0;
and I write to a file using fwrite:
FILE *fp = fopen("file.txt",wb);
fwrite(&a,sizeof(unsigned char),1,fp);
fclose(fp);
When I open file I always see 20h, why not 00h?
So, I try to use:
fprintf(fp,"%x",a);
In this case I see 0h, but I need a full byte, not a nibble.
What should I do?
The first example is hard to believe, it ought to generate a file with a single byte with the value 0 in it. That's not really a text file though, so I guess your tools might fool you.
The second attempt is better, assuming you want a text file with a text representation of the value in it. To make it two hexadecimal digits, specify a width and padding:
fprintf(fp, "%02x", a);
Please note that there is no such thing as "a hex value". A value is a value; it can be represented as hex, but that's not part of the value. 100 decimal is the same thing as 64 in hex, and 1100100 in binary. The base only matters when representing the number as a string of digits, the number itself can't "be hex".

Difference between binary and text file in terms of storage?

I want to ask few questions about bits and bytes as I am very confused.
For example, suppose I have a short int x = 345;. I know that short take 16 bits, so when I write the short in a file it is written as char '3' , '4' ,'5' each containing 1 bytes so total of 24 bits.
Is there a way to write the number (short integer) in file as short integer taking 16 bits?
Also am I right in my concept? What will be the difference in writing to my file if the file is binary or text in terms of bytes?
Yes, there is a way.
uint16_t sh = 345;
fwrite(&sh, sizeof(sh), 1, fp);
In the case you mentioned 345 is written as text (for example ASCII if that's what you use). In the example I posted, the binary representation of sh is written in the file and it will take only 2 bytes.
What will be the difference in writing to my file if the file is
binary or text in terms of bytes?
Text write (fprintf)
0000000: 00110011 00110100 00110101
3 4 5
Binary write (fwrite)
0000000: 01011001 00000001
#Little endian. Read as: 00000001 01011001 = 345
If interoperabillity is an issue (i.e. you want to send the file to another machine) the text format is a superior choice as it's portable.
If you write the value as a string, it will occupy at least three bytes for the three digits; there would often be a newline or space as well to mark the end of the value.
Yes, you can write the value as 2 bytes. One way would be:
fwrite(&x, sizeof(x), 1, fp);
The difference between binary and text is that you can transport the text between different types of machine with almost complete impunity and all the machines will interpret the data the same way. The binary file can only be interpreted on machines that have the same endian-ness (big-endian or non-Intel vs little-endian or Intel). On the other class of machines, you have to swap the order of the bytes to get the binary data interpreted correctly.

Resources