I have a file 'data.dat' with 26 hex byte values:
22 49 E1 09 62 18 42 8C 66 10 B0 11 84 9C 00 FF E0 40 1F F8 60 07 FE 2C 03 FF
I am trying to read these into c and print the hex values to the terminal with:
const int msgbuflen = 26;
char message [msgbuflen];
const char* filenameIn = "data.dat";
FILE* fpIn = fopen(filenameIn, "rb");
if (!fpIn) {
perror("ERROR: INPUT FILE CANNOT BE OPENED\n");
exit(EXIT_FAILURE);
}
for (i=0; i<msgbuflen; i ){ // clear the buffer
message[i] = '0';
}
size_t ret_code = fread(message, sizeof(unsigned char), msgbuflen, fpIn);
for(int i = 0; i < msgbuflen; i ){
printf("message[%d] : 0x%x\n", i, message[i]);
}
fclose (fpIn);
When run the output for some of the bytes have 3 leading ff values:
message[0] : 0x22
message[1] : 0x49
message[2] : 0xffffffe1
message[3] : 0x9
message[4] : 0x62
message[5] : 0x18
message[6] : 0x42
message[7] : 0xffffff8c
message[8] : 0x66
message[9] : 0x10
message[10] : 0xffffffb0
message[11] : 0x11
message[12] : 0xffffff84
message[13] : 0xffffff9c
message[14] : 0x0
message[15] : 0xffffffff
message[16] : 0xffffffe0
message[17] : 0x40
message[18] : 0x1f
message[19] : 0xfffffff8
message[20] : 0x60
message[21] : 0x7
message[22] : 0xfffffffe
message[23] : 0x2c
message[24] : 0x3
message[25] : 0xffffffff
Why do these leading f's occur? for example message[2] : 0xffffffe1
I have tried formatting the output of the printf hex %x with 0xx but it makes no difference to the terminal output. Checking the sizeof each element in the char array, they are still 1 byte as expected:
printf("sizeof(message[2]) : %ld\n", sizeof(message[2]) );
%> sizeof(message[2]) : 1
I am now wondering if this is a formatting problem? There does not appear to be any more than 1 byte in each message element (as expected).
Using std::hex with cout produces the same issue.
CodePudding user response:
This is because char
is a signed integer so 0xFF
becomes -1
. As %x
prints an int
, which is 32-bits, it becomes 0xFFFFFFFF
which is a 32-bit negative one.
If you store as an unsigned char
you will not have this problem
#include <cstdio>
int main() {
unsigned char message[] = {0x22, 0x49, 0xE1, 0x09, 0x62, 0x18, 0x42, 0x8C, 0x66, 0x10, 0xB0, 0x11, 0x84, 0x9C, 0x00, 0xFF, 0xE0, 0x40, 0x1F, 0xF8, 0x60, 0x07, 0xFE, 0x2C, 0x03, 0xFF };
int msgbuflen = sizeof(message)/sizeof(message[0]);
for(int i = 0; i < msgbuflen; i ){
printf("message[%d] : 0x%x\n", i, message[i]);
}
}
Produces
Program returned: 0
message[0] : 0x22
message[1] : 0x49
message[2] : 0xe1
message[3] : 0x9
message[4] : 0x62
message[5] : 0x18
message[6] : 0x42
message[7] : 0x8c
message[8] : 0x66
message[9] : 0x10
message[10] : 0xb0
message[11] : 0x11
message[12] : 0x84
message[13] : 0x9c
message[14] : 0x0
message[15] : 0xff
message[16] : 0xe0
message[17] : 0x40
message[18] : 0x1f
message[19] : 0xf8
message[20] : 0x60
message[21] : 0x7
message[22] : 0xfe
message[23] : 0x2c
message[24] : 0x3
message[25] : 0xff
Godbolt: https://godbolt.org/z/oxPqnYqMq
Alternatively you can just cast
for(int i = 0; i < msgbuflen; i ){
printf("message[%d] : 0x%x\n", i, (unsigned char)message[i]);
}
CodePudding user response:
Or in somewhat more current C (not using "C" style arrays) and a well defined unsigned 8 bits datatype. (char can be either signed or unsigned depending on the platform you are working on)
#include <array>
#include <iostream>
#include <sstream>
#include <cstdint>
#include <format>
// simulated opening of a std::ifstream
auto open_file()
{
static std::array<std::uint8_t,26> data
{
0x22, 0x49, 0xE1, 0x09, 0x62, 0x18, 0x42, 0x8C, 0x66, 0x10,
0xB0, 0x11, 0x84, 0x9C, 0x00, 0xFF, 0xE0, 0x40, 0x1F, 0xF8,
0x60, 0x07, 0xFE, 0x2C, 0x03, 0xFF
};
std::istringstream is(std::string{ data.begin(), data.end() });
return is;
}
int main()
{
std::array<std::uint8_t, 26> buffer;
auto is = open_file();
// get doesn't have an overload for std::uint8_t*
// so check if sizeof char matches sizeof std::uint8_t
static_assert(sizeof(char) == sizeof(std::uint8_t));
is.get(reinterpret_cast<char*>(buffer.data()), buffer.size());
for (const auto byte : buffer)
{
std::cout << std::format("0x{:x} ", byte);
}
return 0;
}