Reputation: 147
I am trying to convert integers into byte (aka unsigned char) arrays to send the array over a TCP Stream in C++ and vice versa.
I have tried many solutions on stackoverflow and own ideas but nothing really seems to work for me.
My last solution looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include "tcpconnector.h"
typedef unsigned char byte;
using namespace std;
/*
char* byteToChar(byte* b, int length) {
char c[length];
for (int i = 0; i < length; i++) {
c[i] = b[i] - 128;
}
return c;
}
byte* charToByte(char* c, int length) {
byte b[length];
for (int i = 0; i < length; i++) {
b[i] = c[i] + 128;
}
return b;
}
*/
byte* intToByte(int n) {
byte byte[4];
byte[0] = n & 0x000000ff;
byte[1] = n & 0x0000ff00 >> 8;
byte[2] = n & 0x00ff0000 >> 16;
byte[3] = n & 0xff000000 >> 24;
return byte;
}
int byteToInt(byte* byte) {
int n = 0;
n = n + (byte[0] & 0x000000ff);
n = n + ((byte[1] & 0x000000ff) << 8);
n = n + ((byte[2] & 0x000000ff) << 16);
n = n + ((byte[3] & 0x000000ff) << 24);
return n;
}
int main(int argc, char** argv)
{
if (argc != 3) {
printf("usage: %s <port> <ip>\n", argv[0]);
exit(1);
}
int number = 42;
byte* line = intToByte(number);
cout << "Number: " << number << "\n";
cout << "ArrayLength: " << sizeof line << "\n";
cout << "Array: " << line << "\n";
cout << "Array to Number: " << byteToInt(line) << "\n";
/*
TCPConnector* connector = new TCPConnector();
TCPStream* stream = connector->connect(argv[2], atoi(argv[1]));
if (stream) {
stream->send(byteToChar(line, 4), 4);
delete stream;
}
*/
exit(0);
}
Everytime I execute this code I get the result "4202308" no matter what I set as "int number".
Any help would be appreciated.
UPDATE:
void intToByte(int n, byte* result) {
result[0] = n & 0x000000ff;
result[1] = n & 0x0000ff00 >> 8;
result[2] = n & 0x00ff0000 >> 16;
result[3] = n & 0xff000000 >> 24;
}
Excerpt from main():
int number = 42;
byte line[4];
intToByte(number, line);
cout << "Number: " << number << "\n";
cout << "ArrayLength: " << sizeof line << "\n";
cout << "Array: " << line << "\n";
cout << "Array to Number: " << byteToInt(line) << "\n";
Upvotes: 4
Views: 12697
Reputation: 19
In case someone is looking for modern C++20 solution (with <bit>
in standard library).
Here are two nice and templated functions to convert fundamental types (like int, short, etc.) to bytes with conversion to necessary endianness:
template<typename T, std::endian to_endianness = std::endian::big>
std::vector<uint8_t> toBytes(T value)
{
std::vector<uint8_t> buffer(sizeof(T));
std::copy_n(reinterpret_cast<uint8_t*>(&value), sizeof(T), buffer.begin());
if constexpr (std::endian::native != to_endianness)
std::reverse(buffer.begin(), buffer.end());
return buffer;
}
...and to convert from bytes you can use:
template<typename T, std::endian from_endianness = std::endian::big>
T fromBytes(std::vector<uint8_t> bytes)
{
if constexpr (std::endian::native != from_endianness)
std::reverse(bytes.begin(), bytes.end());
T* buffer = reinterpret_cast<T*>(bytes.data());
return *buffer;
}
To keep code in this answer simple I have intentionally removed checks for mixed endianness and std::is_fundamental<T>
, you can see code with these checks on my GitHub gist (Unlicense license) if you need to.
Upvotes: 1
Reputation: 880
This function convert all standard type in c++ to byte vector.
template <typename T>
std::vector<byte> ToByte(T input)
{
byte* bytePointer = reinterpret_cast<byte*>(&input);
return std::vector<byte>(bytePointer, bytePointer + sizeof(T));
}
Upvotes: 2
Reputation: 342
First point:
The buffer you are returning from byte* intToByte(int n)
is not safe.
You are returning the base address of a local array. Either pass a byte array as input or allocate the byte in heap and return the address
Second point:
Consider operator precedence.
byte byte[4];
byte[0] = n & 0x000000ff;
byte[1] = ( n & 0x0000ff00 ) >> 8;
byte[2] = ( n & 0x00ff0000 ) >> 16;
byte[3] = ( n & 0xff000000 ) >> 24;
Upvotes: 2
Reputation: 3529
Your intToByte
function is allocating a byte[4]
within the scope of its body and then returning a pointer to it.
Consequently, the value is trashed as soon as your function returns and all the caller receives is a pointer to a now-invalid location - values are destroyed when they go out of scope and pointers do not extend that lifetime.
Either use a standard container object such as std::array
or std::vector
which your function should return to the caller or alternatively, have intToByte
accept a byte[4]
/byte*
as an argument and fill it in.
For completeness... you could also have the function create the byte array using new
, but then you'd have to remember to delete[]
it, which, whilst seemingly an easy thing to do in this case, is generally bad practice when you have no good reason to make a dynamic allocation.
Additionally, the statement x & y >> z
will first perform y >> z
and then bitwise-AND the result with x
, which is of course not what you want.
Upvotes: 4
Reputation: 520
Unfortunately this is not an exact answer to your question but may be helpful. YOu can do it like in the below code I think.
#include <stdio.h>
using namespace std;
unsigned char* intToByte(const int& N) {
unsigned char* byte = new unsigned char[4];
byte[0] = (N >> 24) & 0xFF;
byte[1] = (N >> 16) & 0xFF;
byte[2] = (N >> 8) & 0xFF;
byte[3] = N & 0xFF;
return byte;
}
int main()
{
unsigned char * result = intToByte(255);
printf("%x %x %x %x\n", (unsigned char)result[0], (unsigned char)result[1],
(unsigned char)result[2], (unsigned char)result[3]);
delete result;
return 0;
}
Upvotes: 0