What is `4` doing in this `memcy()` function in C++? - c++

Below is a struct that I have and a variable of the type of this struct RtpHeader.
typedef struct _RTP_header
{
unsigned char csrc : 4;
unsigned char extension : 1;
unsigned char padding : 1;
unsigned char version : 2;
unsigned char payload : 7;
unsigned char marker : 1;
unsigned short seq;
unsigned int ts;
unsigned int ssrc;
} RtpHeader;
RtpHeader rtp_header;
rtp_header.version = 2;
rtp_header.payload = 96;
rtp_header.marker = 1;
rtp_header.seq = 0;
rtp_header.ts = htonl(std_random_device());
rtp_header.ssrc = htonl(std_random_device());
std::shared_ptr<char> buf;
// binary data is assigned to the buf variable here... (out of scope of this question.
memcpy(buf.get() + 4, &rtp_header, 12);
I do understand what the memcpy() fuction does. But I don't understand what + 4 does here.

The get() function of the std::shared_ptr returns the raw pointer to the data object that it shared.
In this case it will point to the raw char.
The +4 simply moves an additional 4 char sized memory positions.
If the shared object were to be a char[10] buffer, it would point at the 5th element in that array, buffer[4].
In your example there is no buffer, but a single char. In this case the result is undefined.

Related

How to Memcopy and copy back to a char array?

I would like to copy a variable of 1 byte to relatively larger char array, and copy it back? How can I do that?
/* memcpy example */
#include <stdio.h>
#include <string.h>
struct Data {
unsigned char name[40];
int age;
};
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
int main ()
{
uint8_t myval = 8;
uint8_t myval_2 = 8;
Data mypass;
memcpy(&mypass.name, &myval, sizeof(uint8_t));
memcpy(&mypass.name+1, &myval_2, sizeof(uint8_t));
uint8_t* myvalnew = nullptr;
uint8_t* myvalnew_2 = nullptr;
memcpy(myvalnew, (uint8_t*)&mypass.name, sizeof(uint8_t));
memcpy(myvalnew_2, (uint8_t*)&mypass.name+1, sizeof(uint8_t));
return 0;
}
However I am getting errors.
&mypass.name creates a pointer to your name array, you want a pointer to the first element of your array, you can use either simply mypass.name or &mypass.name[0]. memcpy is unnecessary here as you can simply assign the elements:
mypass.name[0] = myval;
mypass.name[1] = myval_2;
Your second set of memcpys will fail as your myvalnew pointers are null, I'm not sure what you're trying to achieve here. If you're trying to get the values back you can again just use normal array access:
uint8_t myvalnew = mypass.name[0];
uint8_t myvalnew_2 = mypass.name[1];

Store value in pointer var

How to store int values in *pData and display values from it?
int id = 12;
int age = 14;
unsigned char* pData = new unsigned char[8];
memcpy(pData,&id,4);/* using memcpy to copy */
pData = pData + 4;
memcpy(pData,&age,4);/* using memcpy to copy */
// How to print value from buffer *pData
After using memcpy to copy the bytes of an int into an unsigned char buffer, the only correct way to display the ints is to copy the bytes back into an int. For example:
int temp_int;
memcpy(&temp_int, pData, sizeof temp_int);
std::cout << temp_int << '\n';
memcpy(&temp_int, pData + sizeof temp_int, sizeof temp_int);
std::cout << temp_int << '\n';
Attempting to reinterpret the buffer as an int would cause undefined behaviour by violating the strict aliasing rule.
you can change pData into int *, then you can print the int valve.
cout<<*((int *)pData);
memcpy(pData,&id,4);
This line copies the four bytes data in id to pData as int but you declared it as char * .
if you declare it as int *pData = new int[2]; then you can ptint exact values.
using namespace std;
int id = 12;
int age = 14;
unsigned int* pData = new unsigned int[2];
memcpy(pData,&id,4);
pData = pData + 1;
memcpy(pData,&age,4);
pData = pData - 1;
cout<<"ID:"<<pData[0]<<"\nAge:"<<pData[1]<<endl;
This will print the values.
If you really need to allocate memory as unsigned char*, you can do it like below:
#include <iostream>
#include <cstring>
using namespace std;
int main() {
int id = 12;
int age = 14;
// const pointer to buffer which can contain 2 ints
unsigned char* const pData = new unsigned char[2*sizeof(int)];
// non-const pointer to operate on data
unsigned char* pDataPtr = pData;
memcpy(pDataPtr,&id,sizeof(int));
pDataPtr += sizeof(int);
memcpy(pDataPtr,&age,sizeof(int));
std::cout<<*reinterpret_cast<int*>(pData)<<std::endl;
std::cout<<*reinterpret_cast<int*>(pData + sizeof(int))<<std::endl;
delete [] pData;
return 0;
}
You can print pData using reinterpret_cast operator :
#include <iostream>
#include <cstring>
int main(void)
{
int id = 12;
int age = 14;
const size_t size = sizeof(int);
unsigned char* pData = new unsigned char[2*size];
memcpy(pData,&id,size);/* using memcpy to copy */
pData = pData + size;
memcpy(pData,&age,size);/* using memcpy to copy */
std::cout<<*reinterpret_cast<int*>(pData)<<std::endl;
pData = pData - size;
std::cout<<*reinterpret_cast<int*>(pData)<<std::endl;
delete []pData;
return 0;
}

how to return char array in c++? array length is determined in the function itself

char *readByteArray() {
unsigned char l = readByte (); // reads one byte from the stream
char ret[l + 1]; // this should not be done
ret[0] = l; // or could also define a struct for this like {int length, char *data}
readBytes((char *)&ret + 1, l);
return (char *)&ret;
}
So the problem is, that I want to return an array, and the length of the array is determined by the function.
A better example of this would be the function I use for reading a string:
char *readString () {
unsigned char l = readByte (); // reads one byte from the stream
char ret[l + 1]; // +1 for null byte
readBytes((char *)&ret, l); // reads l bytes from the stream
ret[l] = '\0'; // null byte
return (char *)&ret; // problem
}
If the length of the array would be determined before the function I could allocate the array outside the function and pass it as a parameter, but calling this:
unsigned char l = readByte ();
char ret[l + 1];
readString (&ret, l);
every time I want to read a string would kind of defeat the purpose of the function.
Is there an elegant solution for this on windows AND ATmega328 (STL is not available)?
One of the following options should work:
Return a pointer to an array of char allocated from the heap. Make sure to delete the returned value in the calling function.
char* readByteArray()
{
unsigned char l = readByte();
char *ret = new char[l + 1];
ret[0] = l;
readBytes(ret + 1, l);
return ret;
}
Return a std::vector<char>.
std::vector<char> readByteArray()
{
unsigned char l = readByte();
std::vector<char> ret(l);
readBytes(ret.data(), l);
return ret;
}

Get string from starting index to end from char Array

I have an object with a char Array; where the first 5 bytes(char in C++) are additional data and everything afterwards is a string message.
So my question is how can I get a string from starting index 5 way up to the last byte?
I know there is memccpy, but it requires an ending char, which I can't know beforehand.
I am aware there is a string object in C++, but the idea is to send back and forth a byte array which contains the data and message. So in a sense I serialize and deserialize back and forth.
Any suggestions?
Edit:
Packet * Packet::create(byte const data[])
{
//Concat all first 4 byte values to a uint32
unsigned int length = data[0] << 32 | data[1] << 16 | data[2] << 8 | data[3] << 0;
//4th element is packet type
PacketType type = (PacketType)data[4];
string packetData;
packetData.clear();
char * cdata;
//Check packet data is present
if(sizeof(data) > 5)
{
//string s((char)data);
//packetData = s.substr(4, s.length() - 4);
strncat(cdata,data+5,sizeof(data)-5);
packetData.append(cdata);
}
//Create new packet;
Packet * packet = new Packet(length,type,packetData);
return packet;
};
It won't accept data[] even when I cast it to char.
The argument isn't a pointer?
Edit::
Packet * Packet::create(char const * data)
{
//Concat all first 4 byte values to a uint32
unsigned int length = data[0] << 32 | data[1] << 16 | data[2] << 8 | data[3] << 0;
//4th element is packet type
PacketType type = (PacketType)data[4];
//Set packet data, if available
string packetData = (sizeof(data) > 5) ? string(data+5):"";
Packet * packet = new Packet(length,type,packetData);
return packet;
};
I still have to test this, but I had to use char, how do I use my own typedef in this situation?
Also what is the difference between
"char * data"
and
"char data[]"
I thought arrays and pointers are one and the same thing.
You mentioned "know there is memccpy, but it requires an ending char, which I can't know beforehand". Does that means that your serialized data doesn't have neither the size of the data nor a delimiter? Without that how do you expect
"string packetData = (sizeof(data) > 5) ? string(data+5):"";"
to work?
For the serialization you could send the size of your data as well in the header. Then use the simple memcpy.
use strcpy with charArray + 5 as source parameter.
You should also know of strlen which gives you the string's length [might be needed to allocate the char[], if there is not known upper bound for it].
EDIT: code snap:
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char in[] = "XXXXXqwerty";
//dynamic allocation using strlen() if you don't have upper bound for in
char* out = new char[strlen(in) - 4];
strcpy(out,in+5);
cout << out;
delete[] out;
return 0;
}

storing and reading int data into char array

I am trying to store two integer value into an char array in C++.
Here is the code..
char data[20];
*data = static_cast <char> (time_delay); //time_delay is of int type
*(data + sizeof(int)) = static_cast<char> (wakeup_code); //wakeup_code is of int type
Now on the other end of the program, I want to reverse this operation. That is, from this char array, I need to obtain the values of time_delay and wakeup_code.
How can I do that??
Thanks,
Nick
P.S: I know this is a stupid way to do this, but trust me its a constraint.
I think when you write static_cast<char>, that value is converted to a 1-byte char, so if it didn't fit in a char to begin with, you'll lose data.
What I'd do is use *((int*)(data+sizeof(int))) and *((int*)(data+sizeof(int))) for both reading and writing ints to the array.
*((int*)(data+sizeof(int))) = wakeup_code;
....
wakeup_code = *((int*)(data+sizeof(int)));
Alternatively, you might also write:
reinterpret_cast<int*>(data)[0]=time_delay;
reinterpret_cast<int*>(data)[1]=wakeup_code;
If you are working on a PC x86 architecture then there are no alignment problems (except for speed) and you can cast a char * to an int * to do the conversions:
char data[20];
*((int *)data) = first_int;
*((int *)(data+sizeof(int))) = second_int;
and the same syntax can be used for reading from data by just swapping sides of =.
Note however that this code is not portable because there are architectures where an unaligned operation may be not just slow but actually illegal (crash).
In those cases probably the nicest approach (that also gives you endianness control in case data is part of a communication protocol between different systems) is to build the integers explicitly in code one char at a time:
first_uint = ((unsigned char)data[0] |
((unsigned char)data[1] << 8) |
((unsigned char)data[2] << 16) |
((unsigned char)data[3] << 24));
data[4] = second_uint & 255;
data[5] = (second_uint >> 8) & 255;
data[6] = (second_uint >> 16) & 255;
data[7] = (second_uint >> 24) & 255;
I haven't tried it, but the following should work:
char data[20];
int value;
memcpy(&value,data,sizeof(int));
Try the following:
union IntsToChars {
struct {
int time_delay;
int wakeup_value;
} Integers;
char Chars[20];
};
extern char* somebuffer;
void foo()
{
IntsToChars n2c;
n2c.Integers.time_delay = 1;
n2c.Integers.wakeup_value = 2;
memcpy(somebuffer,n2c.Chars,sizeof(n2c)); //an example of using the char array containing the integer data
//...
}
Using such union should eliminate the alignment problem, unless the data is passed to a machine with different architecture.
#include <sstream>
#include <string>
int main ( int argc, char **argv) {
char ch[10];
int i = 1234;
std::ostringstream oss;
oss << i;
strcpy(ch, oss.str().c_str());
int j = atoi(ch);
}