Writing DWORD to memory overwrites only 1 byte instead of 4 - c++

I have
typedef unsigned int DWORD;
void write_str(string str, char** buf) {
DWORD len = str.size();
**buf = len;
*buf += sizeof(len);
memcpy(*buf, str.c_str(), len);
*buf += len;
}
This code, and only 1 byte is overwriten in **buf = len; if i have i.e. 7 in len while 4 should be, since sizeof(DWORD) = 4

As buf is a char **, **buf is a char. It can hold only a single byte. Therefore, only a single byte is written to it.

Fix:
DWORD *tmpptr(*buf);
*tmpptr = len;
C++ is automatically casting len to a char, since that is what *buf is.

You have the parameter
char** buf
Meaning that **buf is a char, which is very likely a single byte.

1 byte is overwritten since the destination type is char (the type of **buf is char). This is correct. But the expression *buf += sizeof(len) has no meaning in my opinion.

Related

c++ uint8_t* needs to be converted to an integer

I am fairly new to c++
I have function that has a return parameter an unsigned char*. I need to convert the return parameter to an integer.
I declare my return value as:
int length = 3;
uint8_t *transmit = new uint8_t[length];
uint8_t *receive= new uint8_t[length];
int tmp = SpiWriteAndRead(spiHandle, transmit, receive, (length), holdLow);
The function prototype
int SpiWriteAndRead (SPI_HANDLE spiHandle, uint8_t* TxData, uint8_t* RxData, uint16_t Length, bool LeaveCsLow);
Question is when I get back the receive buffer I need to convert the value to an integer.
How do I convert an uint8_t* to an integer?
The only way I can think of to turn a 3 byte array into a int is to individually or the bytes into the desired type after casting and shifting.
int value = static_cast<int>(receive[0]) << 16 | static_cast<int>(receive[1]) << 8 | static_cast<int>(receive[2]);
A better solution would be to use a length of 4
int length = 4;
uint8_t *transmit = new uint8_t[length];
uint8_t *receive= new uint8_t[length];
int tmp = SpiWriteAndRead(spiHandle, transmit, receive, (length), holdLow);
int value = *reinterpret_cast<int*>(recieve);
Finally, consider avoiding new/delete if possible. int holds 4 bytes just as well as uint8_t[4], no need to convert to and from so much if all you wanted was an int anyways.
uint8_t transmit[sizeof(int)];
int receive = 0;
int tmp = SpiWriteAndRead(spiHandle, &transmit, reinterpret_cast<uint8_t*>(&receive), sizeof(int), holdLow);

Convert char[] to off_t

I stored a filesize in a binary file and I am able to get this filesize into a char[8] buffer. I would like to convert this char[] into an off_t type in order to be able to pass it as an argument of truncate(const char *path, off_t length).
I tried this naive approach and it seems to work most of the time, but it fails sometimes and gives me a weird sequence of bits.
off_t pchar_2_off_t(char* str, size_t size)
{
off_t ret = 0;
size_t i;
for (i = 0; i < size; ++i)
{
ret <<= 8;
ret |= str[i];
}
return ret;
}
ret |= str[i]; is a problem as str[i] may sign-extend upon conversion to int, setting many bits in ret. Implied by #pmg and commented by #mafso
off_t pchar_2_off_t(const char* str, size_t size) {
off_t ret = 0;
size_t i;
for (i = 0; i < size; ++i) {
ret <<= 8;
ret |= (unsigned char) str[i];
}
return ret;
}
Just bulk-copy the data in question:
#include <string.h> /* for memcpy() */
...
char str[8];
/* Read 8 bytes binary data into str here. */
off_t off_file;
memcpy(&off_file, str, sizeof off_file);
To get around any endiness issues just do:
off_t off = ntohll(off_file); /* Assuming ntohll being the 64bit version of ntohl(). */
As ntohll() is non-standard please see some possible ways to implement it here: 64 bit ntohl() in C++?
unsigned const char blah[8] = {0xdd,0xee,0xaa,0xdd,0xbb,0xee,0xee,0xff};
off_t * scalar = (off_t *) malloc(8);
memcpy(scalar, blah, 8);
printf("%llx\n",*scalar);
outputs(on my intel machine): ffeeeebbddaaeedd
what the wha?! you say.... there is a problem with this approach, and it is that it isn't portable ... it is a problem with endianness ...
so if you want to do this portably you need to actually either be aware of endianness and special case it or just convert with a loop:
*scalar = 0;
for (int i = 0; i < 8; i++)
{
*scalar += (uint64_t)blah[i] << ( 8 * (7-i));
}
printf("%llx\n",*scalar);
outputs (on all machines that have 64bit off_t's): ddeeaaddbbeeeeff
Assuming the file that contains the filesize was created on the EXACT same machine AND that it was originally written with an off_t type, you can just cast the char[] -> an off_t. eg:
off_t filesize = *((off_t*)str);

Converting 4 bytes in little endian order into an unsigned integer

I have a string of 256*4 bytes of data. These 256* 4 bytes need to be converted into 256 unsigned integers. The order in which they come is little endian, i.e. the first four bytes in the string are the little endian representation of the first integer, the next 4 bytes are the little endian representation of the next integer, and so on.
What is the best way to parse through this data and merge these bytes into unsigned integers? I know I have to use bitshift operators but I don't know in what way.
Hope this helps you
unsigned int arr[256];
char ch[256*4] = "your string";
for(int i = 0,k=0;i<256*4;i+=4,k++)
{
arr[k] = ch[i]|ch[i+1]<<8|ch[i+2]<<16|ch[i+3]<<24;
}
Alternatively, we can use C/C++ casting to interpret a char buffer as an array of unsigned int. This can help get away with shifting and endianness dependency.
#include <stdio.h>
int main()
{
char buf[256*4] = "abcd";
unsigned int *p_int = ( unsigned int * )buf;
unsigned short idx = 0;
unsigned int val = 0;
for( idx = 0; idx < 256; idx++ )
{
val = *p_int++;
printf( "idx = %d, val = %d \n", idx, val );
}
}
This would print out 256 values, the first one is
idx = 0, val = 1684234849
(and all remaining numbers = 0).
As a side note, "abcd" converts to 1684234849 because it's run on X86 (Little Endian), in which "abcd" is 0x64636261 (with 'a' is 0x61, and 'd' is 0x64 - in Little Endian, the LSB is in the smallest address). So 0x64636261 = 1684234849.
Note also, if using C++, reinterpret_cast should be used in this case:
const char *p_buf = "abcd";
const unsigned int *p_int = reinterpret_cast< const unsigned int * >( p_buf );
If your host system is little-endian, just read along 4 bytes, shift properly and copy them to int
char bytes[4] = "....";
int i = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
If your host is big-endian, do the same and reverse the bytes in the int, or reverse it on-the-fly while copying with bit-shifting, i.e. just change the indexes of bytes[] from 0-3 to 3-0
But you shouldn't even do that just copy the whole char array to the int array if your PC is in little-endian
#define LEN 256
char bytes[LEN*4] = "blahblahblah";
unsigned int uint[LEN];
memcpy(uint, bytes, sizeof bytes);
That said, the best way is to avoid copying at all and use the same array for both types
union
{
char bytes[LEN*4];
unsigned int uint[LEN];
} myArrays;
// copy data to myArrays.bytes[], do something with those bytes if necessary
// after populating myArrays.bytes[], get the ints by myArrays.uint[i]

Trouble with unsigned char *

I am having trouble with unsigned char *. Here is my code:
unsigned char *str=NULL;
str= (unsigned char*) realloc(str, 10*sizeof(unsigned char));
int number=10;
str[0]=(unsigned char) number;
Whenever I try to see str[0] with cout, it shows something else other than 10. I also have trouble when putting other variable into str:
unsigned char c='c';
str[0]=c;
cout<<str[0];
str[0] would output a. What am I missing?
s[0] = 10; means put character code 10 into the first location of array s. Try:
s[0] = '1'; s[1] = '0'; s[2] = '\0';
Probably you would like instead to use the function itoa(10, s, 10);
See itoa manual, the function itoa is declared as...
char* itoa(int valueToConvert, char* outputBuffer, int base);
If you try to do cout << character; it will print the character, not the character code. To print the character code you should do cout << (int)character;. Don't use unsigned char for characters, characters are, well, signed chars, simply chars, for friends.

copying a short int to a char array

I have a short integer variable called s_int that holds value = 2
unsighed short s_int = 2;
I want to copy this number to a char array to the first and second position of a char array.
Let's say we have char buffer[10];. We want the two bytes of s_int to be copied at buffer[0] and buffer[1].
How can I do it?
The usual way to do this would be with the bitwise operators to slice and dice it, a byte at a time:
b[0] = si & 0xff;
b[1] = (si >> 8) & 0xff;
though this should really be done into an unsigned char, not a plain char as they are signed on most systems.
Storing larger integers can be done in a similar way, or with a loop.
*((short*)buffer) = s_int;
But viator emptor that the resulting byte order will vary with endianness.
By using pointers and casts.
unsigned short s_int = 2;
unsigned char buffer[sizeof(unsigned short)];
// 1.
unsigned char * p_int = (unsigned char *)&s_int;
buffer[0] = p_int[0];
buffer[1] = p_int[1];
// 2.
memcpy(buffer, (unsigned char *)&s_int, sizeof(unsigned short));
// 3.
std::copy((unsigned char *)&s_int,
((unsigned char *)&s_int) + sizeof(unsigned short),
buffer);
// 4.
unsigned short * p_buffer = (unsigned short *)(buffer); // May have alignment issues
*p_buffer = s_int;
// 5.
union Not_To_Use
{
unsigned short s_int;
unsigned char buffer[2];
};
union Not_To_Use converter;
converter.s_int = s_int;
buffer[0] = converter.buffer[0];
buffer[1] = converter.buffer[1];
I would memcpy it, something like
memcpy(buffer, &s_int, 2);
The endianness is preserved correctly so that if you cast buffer into unsigned short *, you can read the same value of s_int the right way. Other solution must be endian-aware or you could swap lsb and msb. And of course sizeof(short) must be 2.
If you don't want to make all that bitwise stuff you could do the following
char* where = (char*)malloc(10);
short int a = 25232;
where[0] = *((char*)(&a) + 0);
where[1] = *((char*)(&a) + 1);