I have the following struct:
typedef union
{
struct
{
unsigned char ID;
unsigned short Vdd;
unsigned char B1State;
unsigned short B1FloatV;
unsigned short B1ChargeV;
unsigned short B1Current;
unsigned short B1TempC;
unsigned short B1StateTimer;
unsigned short B1DutyMod;
unsigned char B2State;
unsigned short B2FloatV;
unsigned short B2ChargeV;
unsigned short B2Current;
unsigned short B2TempC;
unsigned short B2StateTimer;
unsigned short B2DutyMod;
} bat_values;
unsigned char buf[64];
} BATTERY_CHARGE_STATUS;
and I am stuffing it from an array as follows:
for(unsigned char ii = 0; ii < 64; ii++) usb_debug_data.buf[ii]=inBuffer[ii];
I can see that the array has the following (arbitrary) values:
inBuffer[0] = 80;
inBuffer[1] = 128;
inBuffer[2] = 12;
inBuffer[3] = 0;
inBuffer[4] = 23;
...
now I want display these values by changing the text of a QEditLine:
str=QString::number((int)usb_debug_data.bat_values.ID);
ui->batID->setText(str);
str=QString::number((int)usb_debug_data.bat_values.Vdd)
ui->Vdd->setText(str);
str=QString::number((int)usb_debug_data.bat_values.B1State)
ui->B1State->setText(str);
...
however, the QEditLine text values are not turning up as expected. I see the following:
usb_debug_data.bat_values.ID = 80 (correct)
usb_debug_data.bat_values.Vdd = 12 (incorrect)
usb_debug_data.bat_values.B1State = 23 (incorrect)
seems like 'usb_debug_data.bat_values.Vdd', which is a short, is not taking its value from inBuffer[1] and inBuffer[2]. Likewise, 'usb_debug_data.bat_values.B1State' should get its value from inBuffer[3] but for some reason is picking up its value from inBuffer[4].
Any idea why this is happening?
C and C++ are free to insert padding between elements of a structure, and beyond the last element, for whatever purposes it desires (usually efficiency but sometimes because the underlying architecture does not allow unaligned access at all).
So you'll probably find that items of two-bytes length are aligned to two-byte boundaries, so you'll end up with something like:
unsigned char ID; // 1 byte
// 1 byte filler, aligns following short
unsigned short Vdd; // 2 bytes
unsigned char B1State; // 1 byte
// 3 bytes filler, aligns following int
unsigned int myVar; // 4 bytes
Many compilers will allow you to specific how to pack structures, such as with:
#pragma pack(1)
or the gcc:
__attribute__((packed))
attribute.
If you don't want to (or can't) pack your structures, you can revert to field-by-filed copying (probably best in a function):
void copyData (BATTERY_CHARGE_STATUS *bsc, unsigned char *debugData) {
memcpy (&(bsc->ID), debugData, sizeof (bsc->ID));
debugData += sizeof (bsc->ID);
memcpy (&(bsc->Vdd), debugData, sizeof (bsc->Vdd));
debugData += sizeof (bsc->Vdd);
: : :
memcpy (&(bsc->B2DutyMod), debugData, sizeof (bsc->B2DutyMod));
debugData += sizeof (bsc->B2DutyMod); // Not really needed
}
It's a pain that you have to keep the structure and function synchronised but hopefully it won't be changing that much.
Structs are not packed by default so the compiler is free to insert padding between members. The most common reason is to ensure some machine dependent alignment. The wikipedia entry on data structure alignment is a pretty good place to start. You essentially have two choices:
insert compiler specific pragmas to force alignment (e.g, #pragma packed or __attribute__((packed))__.
write explicit serialization and deserialization functions to transform your structures into and from byte arrays
I usually prefer the latter since it doesn't make my code ugly with little compiler specific adornments everywhere.
The next thing that you are likely to discover is that the byte order for multi-byte integers is also platform specific. Look up endianness for more details
Related
I am trying to convert a QString to a qint16 with
udpListenPort = ui->lineEdit_UdpListenPort->text().toShort();
but it converts "40690" to 0.
I tried different casts and conversions but neither works. I think I can't see the wood for the trees here.
The maximal value a qint16 (which is a typedef short qint16; /* 16 bit signed */) can hold is 32767 using two's complement, hence "40690" overflows and signed integer overflow is undefined behaviour.
Use quint16 instead (which is a typedef unsigned short quint16; /* 16 bit unsigned */) and ushort QString::toUShort(bool *ok = nullptr, int base = 10) const.
You came most of the way, just change the toShort() to toUShort() to fix that.
udpListenPort = ui->lineEdit_UdpListenPort->text().toUShort();
quint16 is just a typedef for unsigned short.
I have a pointer to some location in memory passed in, void *dataLoc.
Some program is transferring memory there as a bunch of unsigned chars where 0x00 is 0 and 0xFF is one.
I want to be able to pull, say, every 4th char and convert it to the float of what number is supposed to be represented. But I'm having trouble understanding how I get from a void * to an array of char[] to an array of float[].
My initial thought was to do something like
for(i=0,i<100,i++){
floatArray[i] = (float)(*((unsigned char *)dataLoc[4*i])) / 255;
}
the void * is cast to a char *.
the next 4th char is selected from the for loop
the * dereferences the char pointer, which should give me an unsigned char,
the float should change the char into a float, but a float representation of the number I want *255
I divide by 255 to get the fraction I want.
This fails, because I get the error "pointer of type 'void ' used in arithmetic
'void' is not a pointer-to-object type and beyond this, I'm not really confident that the rest of that line will work out the way I would like.
Can someone advise the proper way to handle this?
Good that you had warnings enabled.
dataLoc[4*i] occurs before (unsigned char *)dataLoc and leads to "pointer of type 'void *' used in arithmetic ..."
Cast to unsigned char * first.
Also remove extra level of *. The following is type unsigned char
((unsigned char *)dataLoc)[4*i]
Fixed:
void * dataLoc;
float floatArray[100];
// for(i=0,i<100,i++){ Use ';', not ','
for(int i=0;i<100;i++){
// Cast to `unsigned char *` before using `[]`
// * not needed here ---v
floatArray[i] = (float)( ( ((unsigned char *)dataLoc) [4*i])) / 255;
}
or
for (int i=0; i<100 ;i++) {
unsigned char value = ((unsigned char *)dataLoc)[4*i];
floatArray[i] = value / 255.0f;
}
So basically I'm working on a file reader and the binary file gets loaded into a std::unique_ptr<unsigned char[]> containing all the bytes from the file.
I'm trying to read an unsigned int from the start of it. Usually, if it were just a raw pointer (unsigned char*) it would be as follows:
unsigned int magic = *(reinterpret_cast<unsigned int*>(buffer));
However, I'm currently trying to the same, where buffer is the smart pointer. So far I've came up with this:
unsigned int magic = *(reinterpret_cast<unsigned int*>(classFile_.get()));
Upon outputting magic like this:
std::cout << std::hex << magic;
I get 1. Where I should be getting: 0xbebafeca (this is a Java class file reader, 0xCAFEBABE is the unsigned int magic number).
Any ideas as to why it's not working? I'm also not sure if storing a smart pointer for the unsigned char* is good practice rather than doing something like storing a raw pointer and deleting the allocated array in the de-constructor.
The reason why I ask this is because there is some strange bug in my code and I suspect it could be some aliasing problem:
__shared__ float x[32];
__shared__ unsigned int xsum[32];
int idx=threadIdx.x;
unsigned char * xchar=(unsigned char *)x;
//...do something
if (threadIdx.x<32)
{
xchar[4*idx]&=somestring[0];
xchar[4*idx+1]&=somestring[1];
xchar[4*idx+2]&=somestring[2];
xchar[4*idx+3]&=somestring[3];
xsum[idx]+=*((unsigned int *)(x+idx));//<-Looks like the compiler sometimes fail to recongize this as the aliasing of xchar;
};
The compiler only needs to honour aliasing between compatible types. Since char and float are not compatible, the compiler is free to assume the pointers never alias.
If you want to do bitwise operations on float, firstly convert (via __float_as_int()) to unsigned integer, then operate on that, and finally convert back to float (using __int_as_float()).
I think you have a race condition here. But I don't know what is somestring. If it is the same for all threads you can do like this:
__shared__ float x[32];
unsigned char * xchar=(unsigned char *)x;
//...do something
if(threadIdx.x<4) {
xchar[threadIdx.x]&=somestring[threadIdx.x];
}
__syncthreads();
unsigned int xsum+=*((unsigned int *)x);
It means that every thread shares the same array and therefore, xsum is the same between all threads. If you want that each thread has its own array, you have to allocate an array of 32*number_of_threads_in_block and use an offset.
PS: the code above works only in 1D block. In 2D or 3D you have to compute you own threadID and be sure that only 4 threads execute the code.
Which of the following two approches is more efficient on an ATmega328P?
unsigned int value;
unsigned char char_high, char_low;
char_high = value>>8;
value = value<<8;
char_low = value>>8;
OR
unsigned int value;
unsigned char char_high, char_low;
char_high = value>>8;
char_low = value & 0xff;
You really should measure. I won't answer your question (since you'd benefit more from measuring than I would), but I'll give you a third option:
struct {
union {
uint16_t big;
uint8_t small[2];
};
} nums;
(be aware of the difference between big endian and little endian here)
One option would be to measure it (as has already been said).
Or, compile both and see what the assembly language output looks like.
but actually, the 2nd code you have won't work - if you take value << 8 and assign it to a char, all you get is zero in the char. The subsequent >>8 will still leave you with zero.