Access int16_t as char* - c++

I'm writing a networking application using sockets in c++ so lets jump straight to the problem :
i'm storing my data as an array of int16_ts (the choice of int16_t being for consistency accross different platforms) , as we know each of these int16_ts would be two consecutive bytes in memory. i want to store each of those bytes in a char so that each int16 would be translated to exactly two bytes and eventually send the entire char* over the socket
please notice that i'm not looking for something such as std::to_string cause i want each int16_t to occupy exactly two bytes.
any help is appreciated !

You would need to copy each int16_t one at a time to the char * buffer, calling htons() on each one to translate the bytes into network byte order. Then on the receiving side, you would call ntohs() to convert back.
int send_array(int16_t *myarray, int len, int socket) {
char buf[1000];
int16_t *p;
int i;
p = (int16_t *)buf;
for (i=0;i<len;i++) {
p[i] = htons(myarray[i]);
}
return send(socket,buf,len*sizeof(int16_t),0);
}

C++ has a new type, char16_t, that's designed to hold UTF-16 characters. If you mean you want to send the 16-bit hints over the wire one byte at a time, convert each one to network byte order with htons(), store them in a new array of uint16_t, then send that array over the socket. If you want to address the array of shorts as an array of bytes, you can do that either through a union, with a pointer cast, or with a reference to an array. Example: char* const p=reinterpret_cast<char*>(&shorts[0]);.

Related

How to create specific size message to send via UDP socket in C++?

I'm trying to write a small application that will "concatenate" a bunch of integer variables of various sizes (uint8, uint16, uint32) into a 128 byte message that will be sent via UDP socket.
On the receiving side, I would like to split the message back into the individual integers and store them for further processing. For now I am assuming that endianness will not be an issue.
Could I get some hints on how to concatenate the int variables and later extract them from that 128 byte message?
So, let's say you expect to recieve data in the following order:
int32_t header; int8_t opcode; int16_t args[32]; int32_t clients[2]; ...
This is just an example, parameters could be whatever they are in your actuai task.
You can wrap those parameters into struct or class. I'd prefer a struct here because it does not seem like you really need to create a ctor, access specifiers or any other fancy stuff class can provide. So, something like that:
#pragma pack(push, 1)
struct DataFromMyHardware {
int32_t header;
int8_t opcode;
int16_t args[32];
int32_t clients[2];
...
};
#pragma pack(pop)
pragmas here used to tell compiler to not optimize placement or alignment of variables in struct, so it'll be stored in memory as is.
This way, you can use this on sender:
DataFromMyHardware buffer;
buffer.header = 0xDEADBEEF;
buffer.opcode = 42;
...
send(socket, &buffer, sizeof(buffer), 0);
and on reciever:
DataFromMyHardware buffer;
recv(socket, (void*)&buffer, sizeof(buffer), 0);
Side note: it's very likely that your device uses network byte-order, so you probably want to use nhohl/ntohs on reciever and htonl/htons on sender.
You can create a character buffer prefix that will precede each integer which will define which type of integer to read so then you can read the correct size of the integer that is defined.
for ex: Precede each integer with a character representing the integer. The first byte will contain the character which you will interpret as an, it could be any ascii character that will represent the integer.
array == [byte][byte-8bit][byte][2 byte-16bit][byte][4 byte -32bit]...
UINT8 = 'a'
UINT16 = 'b'
UINT32 = 'c' or whatever code you want the ascii to be... I used a,b,c so its a readable character you can read in the debugger
You will then have to build your array to be sent with the prefix so you know what size to do your next read.
array = [a0b00c0000a0b00c0000] and so on, you can build the array using memcpy
You can then send the whole packet of 128 bytes
Make sure you read exactly 128 bytes, and then you can deconstruct, remember that when you read you have to check the amount that was read from the socket, and continue to read until you receive the correct amount. -- sometimes a read will not return the correct amount of bytes that you will expect.
When you receive the packet, you can deconstruct the packet using the headers, and depending on the header that you receive you can remove the correct integer and size, and the headers with the correct size should be deconstructed rather easily.
Also remember that UDP is lossy so you will possibly lose packets
Now also remember that if your constructed packet does not equal exactly 128 bytes every time you will need to add another byte which will be equivalent to a integer which will tell you exactly how many bytes were sent... 122..126..127 etc, and read that as the first header on the other side.

Can i use an array of uchars as a single uchar?

I'm making a LZW compressor that records its output in hexadecimal. It currently uses an uchar (OpenCV) for storing values, and outputs the uchar in hexadecimal.
However, I have been asked to allow the user to choose how many bytes are used when storing each value, so he could have, for example, 2 bytes for each value (or 32 bytes, it's up to him).
So, to manipulate the output, I was thinking of using an array of uchars (so, if the user asks for 32 bytes, I use an array of 32 uchars), and the question is: is there an easy way to write a big value to this array and outputting that value later without having to worry about what is in what index and other things? That is, to treat the array as just a x byte uchar? Should I use a vector?
Any help is appreciated.
You could use the following union
union pun_unsigned {
unsigned char c[sizeof(uint64_t)];
uint16_t u16;
uint32_t u32;
uint64_t u64;
};
Note that only conversions from or to (signed or unsigned) char are defined behaviour.

C++: Sending a struct memberwise

I want to send a struct sMessage byte by byte from one microcontroller to another:
typedef struct {
unsigned char mu8MessageId;
unsigned char mu8MessageSenderId;
unsigned char mu8MessageReceiverId;
unsigned short mu16MessageSizePayload;
unsigned short mu16MessageSizeTotal;
} sMessage;
sMessage msMessage;
Therefore I use a simple function
MSGSENDER_vSend(void* pvMessage, unsigned short u16Size)
which takes a void poiner and the size of the data to be sent. At the receiver I receive the sent data byte by byte, and reconstructs the sent data out of it. I have the same byte order on both devices.
Unfortunately I receive the bytes in a different order if I
call this function once with the struct msMessage and its size as parameters (byte order seems to be right)
MSGSENDER_vSend(&msMessage, sizeof(msMessage))
call this function for every member of the struct (byte order is not correct)
MSGSENDER_vSend(&msMessage.mu8MessageId, sizeof(msMessage.mu8MessageId))
MSGSENDER_vSend(&msMessage.mu8MessageSenderId, sizeof(msMessage.mu8MessageSenderId))
//...
Why are the bytes sent in a different order?
Depending on the compiler and the compile flags, there can be "gaps" between the members in the struct. If it optimizes for speed, there is a chance that it will try to align the members according to the largest member type.
In your case you are using 3 1-byte members and 2 2-byte members and may insert 1 byte of void between the last char and the first short so the short is aligned by two (since it's 2 bytes)
Anyway, you should never send (or store) raw structs since they can change if you recompile the application with different flags. The safest way is always to send the data members one by one, then you have full control of the order on the receiving side

Read a Fixed Number of (Binary) Bytes from an unsigned const char*

I have an unsigned const char* buffer in memory (comes from the network) that I need to do some stuff with. What stumps me right now is that I need to interpret the first two bytes as binary data, while the rest is ASCII. I have no problem reading the ASCII (I think), but I can't figure out how to read just the first two bytes of the unsigned array, and turn them into (say) an int. I was going to use reinterpret_cast, but the first two bytes are not null-terminated, and the only other help I could find was all about file IO.
In short, I have something like {0000000000001011}ABC Z123 XY0 5, where the characters outside the curly braces are read as ASCII, while the ones inside are supposed to be a single binary number, i.e. 11).
int c1 = buffer[0];
int c2 = buffer[1];
int number = c1 << 8 + c2;
unsigned char* asciiData = buffer+2;
I really don't get why the bytes have to be "null-terminated" for you to use reinterpret_cast. What I would do (and works so far in my projects) is:
uint16_t first_bytes = *(reinterpret_cast<const uint16_t*>(buffer));
That would get you the first two bytes in the buffer and assign the value to the first_bytes variable.

Change byte in int - casting byte to an integer

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;