This is a simplified C++ program converting 4 bytes into their IEE754 float representation.
#include <iostream>
#include <math.h>
#include <memory.h>
uint8_t bytes[4] = {0x40, 0xd5, 0xc6, 0x7f}; // 0x40d5c67f
float f;
int main()
{
memcpy(&f, &bytes[0], 4);
printf("%.*lf", 5, f);
}
it's output is nan! isnan also returns true for it. How has this happened? 0x40d5c67f is 6.6804...
Happens both on my arduino-like microcontroller and http://cpp.sh/
If you are running this code on a machine that uses little-endian,
higher digits of multi-byte numbers are stored in higher address of the memory.
Therefore, on little endian machines, the 4-byte number on memory
0x40, 0xd5, 0xc6, 0x7f is treated as 0x7fc6d540, not 0x40d5c67f.
Interpreting as IEEE754, the exponent part of this number is 255 and
the fraction part of this number is not 0, so this is NaN.
Related
I need to add a 64 bit floating point number into an unsigned char array at specific indexes (ex. index 1 through 8).
Example unsigned char array:
unsigned char msg[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
I want to add a floating point number like 0.084, for example, which is represented as 1B2FDD240681B53F in hex (little endian) to the unsigned char array at indexes 1,2,3,4,5,6,7,8 and leave indexes 0 and 9 unchanged.
So, I would like the unsigned char array, msg, to contain the following:
msg = {0x00, 0x1B, 0x2F, 0xDD, 0x24, 0x06, 0x81, 0xB5, 0x3F, 0x00}
So far I can get a std::string with the hexadecimal representation of the example floating point value 0.084 using the following code but I'm not sure how to add the string values back into the unsigned char array:
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
int main()
{
union udoub
{
double d;
unsigned long long u;
};
double dVal = 0.084;
udoub val;
val.d = dVal;
std::stringstream ss;
ss << std::setw(16) << std::setfill('0') << std::hex << val.u << std::endl;
std::string strValHexString = ss.str();
cout<< strValHexString << std::endl;
return 0;
}
Output:
3fb5810624dd2f1b
I tried using std::copy like in the example below to copy the values from the std::string to an unsigned char but it doesn't seem to do what I want:
unsigned char ucTmp[2];
std::copy(strValHexString.substr(0,2).begin(), strValHexString.substr(0,2).end(), ucTmp);
Looking for a C or C++ solution.
Formatting the component bytes into a hex string and then reading those back in again is a terrible waste of time and effort. Just use std::memcpy() (in C++) or memcpy (in C):
std::memcpy(&msg[1], &dVal, sizeof(dVal));
This will take care of any required pointer alignment issues. However, it will not do any 'interpretation' in terms of your endianness - but this shouldn't be a problem unless you're then transferring that byte array between different platforms.
Your example has undefined behaviour due to reading from an inactive member of a union. A well defined way to do the conversion to integer:
auto uVal = std::bit_cast<std::uint64_t>(dVal);
Now that you have the data in an integer, you can use bitwise operations to extract individual octets in specific positions:
msg[1] = (uVal >> 0x0 ) & 0xff;
msg[2] = (uVal >> 0x8 ) & 0xff;
msg[3] = (uVal >> 0x10) & 0xff;
msg[4] = (uVal >> 0x18) & 0xff;
msg[5] = (uVal >> 0x20) & 0xff;
...
This can be condensed into a loop.
Note that this works the same way regardless of endianness of the CPU. The resulting order in the array will always be little endian unlike in the direct std::memcpy approach which results in native endianness which is not necessarily little endian on all systems. However, if floating point and integers use different endianness, then the order won't be the same even with this approach.
My array looks something like this;
unsigned char send_bytes[] = { 0x0B, 0x11, 0xA6, 0x05, 0x00, 0x00, 0x70 };
One of the values is a variable that can change all the time.. so I tried something like this;
const char* input = "0x05";
unsigned char send_bytes[] = { 0x0B, 0x11, 0xA6, input, 0x00, 0x00, 0x70 };
When I compile I get a warning;
warning: initialization makes integer from pointer without a cast
I am a little confused on the conversion I need to do.. since the array has hex strings in it.. and the input string is a char..
in the first line you are declaring a pointer to const char, and initializing to the beginning of string "0x05", that's fine, but it is not the thing you are trying to do.
in the second line, you try to initialize the fourth array element (an unsigned char) with the value of the pointer you assigned to the input variable in the first line. The compiler says you are pretending to embed a pointer value (the address of "0x05" string) into a char variable, so that's why it complained. And also it is not what you intend.
also, take into account that if you are using binary data (from the fact you are initializing arrays with hex numbers) you had better to use unsigned char for binaries, as signed char is valid only for -128 to +127 values, you can expect some more unpredictable behaviour. Perhaps, a declaration typedef unsigned char byte; can do things easier.
typedef unsigned char byte;
byte send_bytes[] = { 0x0b, 0x11, 0xa6, 0x00, 0x00, 0x00, 0x70 };
byte &input = send_bytes[3]; /* input is an alias of send_bytes[3] */
BR,
Luis
Maybe explaining exactly what const char* input = "0x05"; does will clear things up for you.
First the compiler computes the string data and creates it as a static object:
const char data[5] = { 0x30, 0x78, 0x30, 0x35, 0x0 };
Then your variable is initialized:
const char *input = &data[0];
Note that input is a pointer with a value that depends entirely upon the location the compiler chooses to store the string data at, and has nothing to do with the contents of the string. So if you say char c = input; then c basically gets assigned a random number.
So you should be asking yourself "Where is the value 0x05 that I want to store in the send_bytes array?" In your code it's encoded as text, rather than as a number that your program can use directly. You need to figure out how to convert from a string of symbols following the hexadecimal scheme of representing numbers into C++'s native representation of numbers.
Here are a couple hints. Part of the operation involves associating values with each digit symbol. The symbol '0' is associated with the value zero, '1' with the value one, and so on, according to the usual hexadecimal system. Second, once you can get the associated value of a symbol, then you can use those values in some basic arithmetic operations to figure out the value of the number represented by the whole string of symbols.
For example, if you have the symbols '1' '2' and 'a', in that order from left to right then the arithmetic to compute what number is represented is 1 * 16 * 16 + 2 * 16 + 10.
The error string is pretty much telling you exactly what's wrong.
input is of type const char* (a pointer to a const char), whereas your array send_bytes is of type unsigned char[] (an array of unsigned chars).
First, signed and unsigned values are still different types, though your error message isn't referring to that specifically.
In reality, your input value isn't a string (as there is no true string type in C++), but a pointer to a character. This means that the input string doesn't hold the byte x05, but rather the bytes {x30, x78, x30, x35, x00}.
The compiler is saying Hey, I've no idea what you're trying to do, so I'm just converting the address that string I don't understand (input) to an unsigned char and adding it to the array.
That means if the string "0x05" starts at location 0xAB, your array will ultimately contain { 0x0B, 0x11, 0xA6, 0xAB, 0x00, 0x00, 0x70 }.
You're going to either have to convert from a string to an integer using a radix of 16, or just not use a string at all.
I'd also recommend reading up on pointers.
The array doesn't have "hex strings" in it - if they were, they would be enclosed in quotation marks, like all strings.
The literals are integers written in hexadecimal notation, and equivalent to
unsigned char send_bytes[] = { 11, 17, 166, input, 0, 0, 112 };
Since it's an array of unsigned char you should put an unsigned char there:
unsigned char input = 0x05;
unsigned char send_bytes[] = { 0x0B, 0x11, 0xA6, input, 0x00, 0x00, 0x70 };
You had better to put in your code:
unsigned char send_bytes[] = { 0x0b, 0x11, 0xa6, 0x00, 0x00, 0x00, 0x70 };
unsigned char &input = send_bytes[3]; /* input is an alias of send_bytes[3] */
this way you can do things like:
input = 0x26;
send_packet(send_bytes);
When using ReadProcessMemory to read memory of an executable file, the first two bytes that I get are reversed. The code is:
SIZE_T dataRead;
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) malloc(1);
ReadProcessMemory(process, (LPVOID)addr, dosHeader, 2, &dataRead);
printf("%x\n", dosHeader->e_magic);
The above outputs 5A4D instead of 4D5A. Why would that be? Could it endianess?
Thanks in advance.
Yes, this is due to endianness. The first byte in the file is 0x4d, the second byte is 0x5a. When you print these using %x, they are interpreted as being a little endian number, so the bytes are swapped when they are printed. Consider, as a self-contained example, the following program:
#include <cassert>
#include <cstdio>
int main()
{
assert(sizeof(unsigned) == 4);
char bytes[4] = { 0x12, 0x34, 0x56, 0x78 };
std::printf("%x\n", *reinterpret_cast<unsigned const*>(bytes));
}
On a system with a little-endian byte ordering, the output will be 78563412. (This example program ignores potential alignment issues; since you are using Visual C++, there will be no problems.)
Note also that you are overrunning your one byte allocation (you malloc(1) but read two bytes).
I'm trying to pullout values from a uint8_t array.
But I'm having troubles understanding how these are represented in the memory.
#include <cstdio>
#include <cstring>
#include <stdint.h>
int main(){
uint8_t tmp1[2];
uint16_t tmp2 = 511;//0x01 + 0xFF = 0x01FF
tmp1[0] = 255;//0xFF
tmp1[1] = 1;//0x01
fprintf(stderr,"memcmp = %d\n",memcmp(tmp1,&tmp2,2));
fprintf(stderr,"first elem in uint8 array = %u\n",(uint8_t) *(tmp1+0));
fprintf(stderr,"first elem in uint8 array = %u\n",(uint8_t) *(tmp1+1));
fprintf(stderr,"2xuint8_t as uint16_t = %u\n",(uint16_t) *tmp1);
return 0;
}
So i have an 2 element long array of datatype uint8_t. And I have a single variable uint16_t.
So when I take the value 511 on my little endian machine, I would assume this is layed out in memory as
0000 0001 1111 1111
But when I use memcompare it looks like it is actually being represented as
1111 1111 0000 0001
So little endianness is only used "within" each byte?
And since the single bit that is set in the tmp1[1] counts as 256, even though it is further "right" in my stream. The values for each byte (not bit), is therefore bigendian? I'm abit confused about this.
Also if I want to coerce an fprint, to printout, my 2xuint8_t as a single uint16_t, how do I do this. The code below doesn't work, it only printouts the first byte.
fprintf(stderr,"2x uint8_t as uint16_t = %u\n",(uint16_t) *tmp1);
Thanks in advance
Your assumption of what you expect is backwards. Your observation is consistent with little-endian representation. To answer your last question, it would look like this:
fprintf(stderr,"2x uint8_t as uint16_t = %u\n",*(uint16_t*)tmp1);
Don't think of endianness as "within bytes". Think of it as "byte ordering". (That is, the actual bit ordering never matters because humans typically read values in big-endian.) If it helps to imagine that the bits are reversed on a little-endian machine, you can imagine it that way. (in that case, your example would have looked like 1111 1111 1000 0000, but as I said, humans don't typically read numbers such that the most significant values are to the right...but you might want to imagine that's how the computer sees things, if it helps you understand little-endian.)
On a little endian machine, 0xAABBCCDD would be seen as 0xDD 0xCC 0xBB 0xAA in memory, just as you are seeing. On a big-endian machine (such as a PPC box) you'd see the same ordering in-memory as you see when you write out the 32-bit word.
First, if you want be 100% sure that your variables are stored in right order in memory, you should put them in a struct.
Then note that memcmp() treats input you give it as a sequence of bytes, since it has no assumptions regarding the nature of the data you give it. Think, for example, of the following code:
#include <stdio.h>
#include <stdint.h>
int main(int argc, char** argv) {
int32_t a, b;
a = 1;
b = -1;
printf( "%i\n", memcmp( &a, &b, sizeof( int32_t ) ) );
}
It outputs -254 on my little-endian machine regardless of fact that a > b. This is because it has no ideas about what the memory actually is, so it compares them like an array of uint8_t.
If you actually want to visualize how the data is represented on your machine, you may first use fwrite to write a struct into the file and then open it with your favorite hex editor (in my experience, wxHexEditor is great in telling you how the data looks if it is X-bit Y-endian ingeter). Here's the source:
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint8_t tmp1[2];
uint16_t tmp2;
} mytmp;
int main(int argc, char** argv) {
mytmp tmp;
tmp.tmp1[0] = 255;
tmp.tmp1[1] = 1;
tmp.tmp2 = 511;
FILE* file = fopen( "struct-dump", "w" );
fwrite( &tmp, sizeof( mytmp ), 1, file );
fclose( file );
}
As for treating an array of uint8_t as uint16_t, you would probably want to declare a union or use pointer coercion.
I have defined the following struct to represent an IPv4 header (up until the options field):
struct IPv4Header
{
// First row in diagram
u_int32 Version:4;
u_int32 InternetHeaderLength:4; // Header length is expressed in units of 32 bits.
u_int32 TypeOfService:8;
u_int32 TotalLength:16;
// Second row in diagram
u_int32 Identification:16;
u_int32 Flags:3;
u_int32 FragmentOffset:13;
// Third row in diagram
u_int32 TTL:8;
u_int32 Protocol:8;
u_int32 HeaderChecksum:16;
// Fourth row in diagram
u_int32 SourceAddress:32;
// Fifth row in diagram
u_int32 DestinationAddress:32;
};
I now also captured an IP frame with Wireshark. As an array literal it looks like this:
// Captured with Wireshark
const u_int8 cIPHeaderSample[] = {
0x45, 0x00, 0x05, 0x17,
0xA7, 0xE0, 0x40, 0x00,
0x2E, 0x06, 0x1B, 0xEA,
0x51, 0x58, 0x25, 0x02,
0x0A, 0x04, 0x03, 0xB9
};
My question is: How can I create a IPv4Header object using the array data?
This doesn't work because of incompatible endianness:
IPv4Header header = *((IPv4Header*)cIPHeaderSample);
I'm aware of the functions like ntohs and ntohl, but it can't figure out how to use them correctly:
u_int8 version = ntohs(cIPHeaderSample[0]);
printf("version: %x \n", version);
// Output is:
// version: 0
Can anyone help?
The most portable way to do it is one field at a time, using memcpy() for types longer than a byte. You don't need to worry about endianness for byte-length fields:
uint16_t temp_u16;
uint32_t temp_u32;
struct IPv4Header header;
header.Version = cIPHeaderSample[0] >> 4;
header.InternetHeaderLength = cIPHeaderSample[0] & 0x0f;
header.TypeOfServer = cIPHeaderSample[1];
memcpy(&temp_u16, &cIPHeaderSample[2], 2);
header.TotalLength = ntohs(temp_u16);
memcpy(&temp_u16, &cIPHeaderSample[4], 2);
header.Identification = ntohs(temp_u16);
header.Flags = cIPHeaderSample[6] >> 5;
memcpy(&temp_u16, &cIPHeaderSample[6], 2);
header.FragmentOffset = ntohs(temp_u16) & 0x1fff;
header.TTL = cIPHeaderSample[8];
header.Protocol = cIPHeaderSample[9];
memcpy(&temp_u16, &cIPHeaderSample[10], 2);
header.HeaderChecksum = ntohs(temp_u16);
memcpy(&temp_u32, &cIPHeaderSample[12], 4);
header.SourceAddress = ntohl(temp_u32);
memcpy(&temp_u32, &cIPHeaderSample[16], 4);
header.DestinationAddress = ntohl(temp_u32);
ntohl and ntohs don't operate on 1-byte fields. They are for 32 and 16 bit fields, respectively. You probably want to start with a cast or memcpy then byte swap the 16 and 32-bit fields if you need to. If you find that version isn't coming through with that approach without any byte swapping, then you have bit field troubles.
Bit fields are a big mess in C. Most people (including me) will advise you to avoid them.
You want to take a look at an the source for ip.h, that one is from FreeBSD. There should be a pre-dedined iphdr struct on your system, use that. Don't reinvent the wheel if you don't have to.
The easiest way to make this work is to take a pointer to the byte array from wireshark and cast it into a pointer to an iphdr. That'll let you use the correct header struct.
struct iphdr* hrd;
hdr = (iphdr*) cIPHeaderSample;
unsigned int version = hdr->version;
Also, htons takes in a 16-bit and changes the byte order, calling it on a 32-bit variable is just going to make a mess of things. You want htonl for 32-bit variables. Also note that for a byte there is no such thing as an endianess, it takes multiple bytes to have different endianess.
Updated:
I suggest you use memcpy to avoid the issues of bitfields and struct alignment, as this can get messy. The solution below works on a simple example, and can be easily extended:
struct IPv4Header
{
uint32_t Source;
};
int main(int argc, char **argv) {
const uint8_t cIPHeaderSample[] = {
0x45, 0x00, 0x05, 0x17
};
IPv4Header header;
memcpy(&header.Source, cIPHeaderSample, sizeof(uint8_t) * 4);
header.Source= ntohl(header.Source);
cout << hex << header.Source<< endl;
}
Output:
45000517