Now there is a unsigned char bytes[4] and I've already known that the byte array is generated from an int in C++. How can I convert the array back to int?
You can do that using std::memcpy():
#include <iostream>
#include <cstring>
int main() {
unsigned char bytes[4]{ 0xdd, 0xcc, 0xbb, 0xaa };
int value;
std::memcpy(&value, bytes, sizeof(int));
std::cout << std::hex << value << '\n';
}
I've already known that the byte array is generated from an int in C++.
It is crucial to know how the array is generated from an int. If the array was generated by simply copying the bytes on the same CPU, then you can convert back by simply copying:
int value;
assert(sizeof value == sizeof bytes);
std::memcpy(&value, bytes, sizeof bytes);
However, if the array may follow another representation than what your CPU uses (for example, if you've received the array from another computer, over the network), then you must convert the representation. In order to convert the representation, you must know what representation the source data follows.
Theoretically, you would need to handle different sign representations, but in practice, 2's complement is fairly ubiquitous. A consideration that is actually relevant in practice is the byte-endianness.
Related
I'm trying to convert a BYTE array into an equivalent unsigned long long int value but my coding is not working as expected. Please help with fixing it or suggest an alternative method for the same.
Extra Information: These 4 bytes are combined as a hexadecimal number and an equivalent decimal number is an output. Say for a Given byteArray= {0x00, 0xa8, 0x4f, 0x00}, Hexadecimal number is 00a84f00 and it's equivalent decimal number is 11030272.
#include <iostream>
#include <string>
typedef unsigned char BYTE;
int main(int argc, char *argv[])
{
BYTE byteArray[4] = { 0x00, 0x08, 0x00, 0x00 };
std::string str(reinterpret_cast<char*>(&byteArray[0]), 4);
std::cout << str << std::endl;
unsigned long long ull = std::strtoull(str.c_str(), NULL, 0);
printf ("The decimal equivalents are: %llu", ull);
return EXIT_SUCCESS;
}
I'm getting the following output:
The decimal equivalents are: 0
While the expected output was:
The decimal equivalents are: 2048
When you call std::strtoull(str.c_str(), NULL, 0);, its first argument supplied is equivalent to an empty string, as string is essentially a null-terminated sequence of characters.
Second, std::strtoull() does not convert with byte sequences, it converts with the literal meaning of strings. i.e. you'll get 2048 with std::strtoull("2048", NULL, 10).
Another thing to note is that unsigned long long is a 64-bit data type, whereas your byte array only provides 32 bits. You need to fill the other 32 bytes with zero to get the correct result. I use a direct assignment, but you could also use std::memset() here.
What you want to do is:
ull = 0ULL;
std::memcpy(&ull, byteArray, 4);
Given your platform has little-endian, the result should be 2048.
What you first must remember is that a string, is really a null-terminated string. Secondly, a string is a string of characters, which is not what you have. The third problem is that you have an array of four bytes, which corresponds to an unsigned 32-bit integer, and you want an (at least) 64-bit types which is 8 bytes.
You can solve all these problems with a temporary variable, a simple call to std::memcpy, and an assignment:
uint32_t temp;
std::memcpy(&temp, byteArray, 4);
ull = temp;
Of course, this assumes that the endianness is correct.
Note that I use std::memcpy instead of std::copy (or std::copy_n) because std::memcpy is explicitly mentioned to be able to bypass strict aliasing this way, while I don't think the std::copy functions are. Also the std::copy functions are more for copying elements and not anonymous bytes (even if they can do that too, but with a clunkier syntax).
Given the answers are using std::memcpy, I want to point out that there's a more idiomatic way of doing this operation:
char byteArray[] = { 0x00, 0x08, 0x00, 0x00 };
uint32_t cp;
std::copy(byteArray, byteArray + sizeof(cp), reinterpret_cast<char*>(&cp));
std::copy is similar to std::memcpy, but is the C++ way of doing it.
Note that you need to cast the address of the output variable cp to one of: char *, unsigned char *, signed char *, or std::byte *, because otherwise the operation wouldn't be byte oriented.
I'm wondering why — in my sample code — when converting a reference to the first element of m_arr to a pointer of bigger size the program reads the memory to m_val in little-endian byte order? With this way of thinking *(std::uint8_t*)m_arr should point to 0x38, but it doesn't.
My CPU uses little-endian byte order.
#include <iostream>
#include <iomanip>
int main() {
std::uint8_t m_arr[2] = { 0x5a, 0x38 };
// explain why m_val is 0x385a and not 0x5a38
std::uint16_t m_val = *(std::uint16_t*)m_arr;
std::cout << std::hex << m_val << std::endl;
return 0;
}
Byte ordering is the order in which bytes are laid out when referenced as their native type. Regardless of whether your machine is big or little endian, a sequence of bytes is always in its natural order.
The situation you describe (where the first byte is 0x38) is what you would observe if you created a uint16_t and got a uint8_t pointer to it. Instead, you have a uint8_t array and you get a uint16_t pointer to it.
Little endian means that the least significant byte goes first:
So translate that logic to your array, { 0x5a, 0x38 }. On a little endian system, the 0x5a is least significant and 0x38 is most significant... hence you get 0x385a.
#include <iostream>
#include <bitset>
typedef struct
{
int i;
char a[4];
uint8_t j:1;
uint8_t k:1;
} abctest;
int main()
{
abctest tryabc;
memset(&tryabc, 0x00, sizeof(tryabc));
std::bitset<1> b;
b = false;
std::cout << b << '\n';
b = true;
std::cout << sizeof(b) << '\n';
}
My doubt is like I have a char array, it is basically a structure received in some module, in this structure I have bit fields also, I can use memcpy but I cannot
Type cast the buffer to structure (for e.g if my char* arr is actually of type struct abc, I cannot do abc* temp = (abc*)arr)
All I can do is memcpy only, So I want to know with out type casting how I can fill the bit fields.
If you know the literal data type and its size in bytes, a variable can be used with bit-shifting to store and extract bits into the array. This is a lower-level function that still exists in C++ but is more related to the low-level programming style of C.
Another way is to use the division and modulo with powers of 2 to encode bits at exact locations. I'd suggest you look up how binary works first and then figure out that shifting to the right by 1 actually divides by 2.
Cheers!
Why can't you typecast a char array into an abctest pointer? I tested it and all works well:
typedef struct
{
int i;
char a[4];
uint8_t j:1;
uint8_t k:1;
} abctest;
int main(int argc, char **argv)
{
char buf[9];
abctest *abc = (abctest*)buf;
memset(buf, 0x00, sizeof(buf));
printf("%d\n", abc->j);
}
However, while you definitely CAN typecast a char array into an abctest pointer, it doesn't mean you SHOULD do that. I think you should definitely learn about data serialization and unserialization. If you want to convert a complex data structure into a character array, typecasting is not the solution as the data structure members may have different sizes or alignment constraints on 64-bit machine than on a 32-bit machine. Furthermore, if you typecast a char array into a struct pointer, the alignment may be incorrect which may result in problems using RISC processors.
You could serialize the code by e.g. writing i as a 32-bit integer in network byte order, a as 4 characters and j and k as two bits in one character (the rest 6 being unused). Then when you unserialize it, you read i from the 32-bit integer in network byte order, the a from 4 characters and the remaining character gives j and k.
I want to convert a double to a 8 length char array in c++. The problem is that I want to cover all the number of bytes of the double type (double is not always 8 byte long in c++).
The char array is just used to store the bytes of the double, as if char type = byte type.
Any ideas?
Yes, you can always treat any object as an array of bytes. To access the bytes, use a reinterpret-cast:
T x; // any object
unsigned char const * bytes = reinterpret_cast<unsigned char const *>)(&x);
for (std::size_t i = 0; i != sizeof(T); ++i)
{
std::fprintf("Byte %zu is %02X\n", bytes[i]); // assuming CHAR_BIT == 8
}
Note that there isn't generally a way to know which of the bytes are part of the object representation and what their actual meaning is. For example, a long double may on certain platforms have size 12 or 16 but only have 10 relevant bytes, and you don't know which one is which. Though for a double with size 8 it's reasonable to assume that there's no padding and that the bytes make up an IEEE-754 representation in linear order. Your platform manual might tell you.
I'm streaming data from the server. Server sends various BigEndian variables, but also sends bytes (representing number). One of my SocketClient.read overloads accepts (int length, char* array). I want to pass an integer variable pointer to this function to get 0-255 value in it (unsigned byte).
What have I tried:
unsigned int UNSIGNED_BYTE;
socket.read(1, &((char*)&UNSIGNED_BYTE)[0]); //I am changing 1st byte of a variable - C++ uses little endian
//I know that function reads 6, and that is what I find in 1st byte
std::cout<<(int)((char*)&UNSIGNED_BYTE)[0]<<")\n"; //6 - correct
std::cout<<UNSIGNED_BYTE<<")\n"; //3435973638 -What the hell?
According to the above, I am changing the wrong part of the int. But what else should I change?
My class declaration and implementation:
/*Declares:*/
bool read(int bytes, char *text);
/*Implements:*/
bool SocketClient::read(int bytes, char *text) {
//boost::system::error_code error;
char buffer = 0;
int length = 0;
while(bytes>0) {
try
{
size_t len = sock.receive(boost::asio::buffer(&buffer, 1)); //Read a byte to a buffer
}
catch(const boost::system::system_error& ex) {
std::cout<<"Socket exception: "<<ex.code()<<'\n';
return false; //Happens when peer disconnects for example
}
if(byteEcho)
std::cout<<(int)(unsigned char)buffer<<' ';
bytes--; //Decrease ammount to read
text[length] = buffer;
length++;
}
return true;
}
So firstly:
unsigned int UNSIGNED_BYTE;
Probably isn't very helpfully named since I very much doubt the architecture you're using defines an int as an 8 bit unsigned integer additionally you're not initializing this to zero and then later you're writing to only part of it leaving the rest as garbage. It's likely to be 32/64 bits in size on most modern compilers/architectures.
Secondly:
socket.read(1, &((char*)&UNSIGNED_BYTE)[0])
Is reading 8 bits into a (probably) 32 bit memory location and the correct end to put the 8 bits is not down to C++ (as you say in your comments). It's actually down to your CPU since endianness is a property of the CPU not the language. Why don't you read the value into an actual char and then simply assign that to an int since this will deal with the conversion for you and will make your code portable.
The problem was, that I did not initialise the int. Though the 1st byte was changed, other 3 bytes had random values.
This makes the solution very simple (and also makes my question be likely to be closed as Too localised):
unsigned int UNSIGNED_BYTE = 0;