DWORD variable with low/high word and low/high byte - c

How in C can we read and make DWORD variables with a low and high word and low and high byte?

WinAPI provides macros for the manipulations of these types, such as:
HIWORD
LOWORD
MAKELPARAM

In Win32 a DWORD is a 32 bit unsigned integer. In other contexts it could possibly mean something else.
Assuminng the Win32 definition (and other Win32 typedefs):
BYTE lsb = 0x11 :
BYTE next_lsb = 0x22 :
BYTE next_msb = 0x33 :
BYTE msb = 0x44 :
DWORD dword_from_bytes = (msb << 24) | (next_msb << 16) | (next_lsb << 8) | lsb ;
dword_from_bytes will have the value 0x44332211.
Similarly:
WORD lsw = 0x1111 :
WORD msw = 0x2222 :
DWORD dword_from_words = (msw << 16) | lsw ;
dword_from_words will have the value 0x22221111.
To extract say the third byte from dword_from_bytes for example:
next_msb = (dword_from_bytes >> 16) & 0xff ;
although the & 0xff is not strictly necessary in this case given the type of next_msb, but if the type of the receiver were larger than 8 bits, it will mask off the msb bits.

#include <stdint.h>
#include <stdio.h>
typedef union _little_endian{
struct _word{
union _msw{
struct _msw_byte{
uint8_t MSB;
uint8_t LSB;
} __attribute__((__packed__)) MSW_BYTE;
uint16_t WORD;
} MSW;
union _lsw{
struct _lsw_byte{
uint8_t MSB;
uint8_t LSB;
} __attribute__((__packed__)) LSW_BYTE;
uint16_t WORD;
} LSW;
} __attribute__((__packed__)) WORD;
uint32_t DWORD;
} DWORD;
int main(int argc, char *argv[]){
DWORD test1;
test1.WORD.MSW.MSW_BYTE.MSB = 1;
test1.WORD.MSW.MSW_BYTE.LSB = 2;
test1.WORD.LSW.LSW_BYTE.MSB = 3;
test1.WORD.LSW.LSW_BYTE.LSB = 4;
printf("test1: hex=%x uint=%u\n", test1.DWORD, test1.DWORD);
DWORD test2;
test2.DWORD = 0x08080404;
printf("test2: hex=%x uint=%u\n", test2.DWORD, test2.DWORD);
printf("test2.WORD.MSW.MSW_BYTE.MSB: uint=%u\n", test2.WORD.MSW.MSW_BYTE.MSB);
printf("test2.WORD.MSW.MSW_BYTE.LSB: uint=%u\n", test2.WORD.MSW.MSW_BYTE.LSB);
printf("test2.WORD.LSW.LSW_BYTE.MSB: uint=%u\n", test2.WORD.LSW.LSW_BYTE.MSB);
printf("test2.WORD.LSW.LSW_BYTE.LSB: uint=%u\n", test2.WORD.LSW.LSW_BYTE.LSB);
return 0;
}
I prefer to use a combination of structs and unions.
Output:
test1: hex=4030201 uint=67305985
test2: hex=8080404 uint=134743044
test2.WORD.MSW.MSW_BYTE.MSB: uint=4
test2.WORD.MSW.MSW_BYTE.LSB: uint=4
test2.WORD.LSW.LSW_BYTE.MSB: uint=8
test2.WORD.LSW.LSW_BYTE.LSB: uint=8

Related

What are for square brackets in an addressed-of pointer?

I've been searching for a while what are for square-brackets in an addressed-of pointer, but I continue without understanding it. Here are the lines of the function, where "id" variable is an uint32_t pointer that has been previously passed as an argument.
#define LIST_STARTED (0x0001) /*defined out of the function*/
#define LIST_FIRST (0x0002) /*defined out of the function*/
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
bool started = *flags & LIST_STARTED;
bool first = *flags & LIST_FIRST;
if (!started){
/* does something */
*flags = MSEC_PRM_MGMT_LIST_STARTED;
return true;
}
if (!first){
/* does something */
*flags |= MSEC_PRM_MGMT_LIST_FIRST;
*index = 1;
return true;
}
if (*index == final_index)
/* does something */
return false;
*index += 1;
I understand what the logic of the function is, but I don't understand what do the following lines. I put "all" the code above in case it helps you.
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
I would appreciate if someone could help me!
Thank you!
I edit to say that this C code works fine in an Embedded System, I'm not modifying it, I was just watching its behaviour.
The following code tries to read a uint32_t object as an array of two uint16_t objects:
uint32_t *id = ...;
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
and that is undefined behaviour to read a uint32_t object as 2 uint16_t objects through flags and index pointers because that breaks strict aliasing rules.
The correct way is:
uint16_t flags = *id; // The lowest order bits of id.
uint16_t index = *id >> 16; // The highest order bits of id.
In the above assignments of uint32_t to uint16_t it truncates the highest order bits of id.
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
it is an equivalent of.
uint32_t *pointer = id;
uint16_t *flags = (uint16_t *)pointer;
The definition:
uint16_t *index = &((uint16_t *)pointer)[1];
Is an equivalent of:
uint16_t *temp = (uint16_t *)pointer;
uint16_t *index = temp + 1;
//or
uint16_t *index = &temp[1];
This is called: pointer punning and it is considered dangerous and not portable.
You can use unions for safe punning (at least when using gcc or its derivatives)
typedef union
{
uint64_t u64;
uint32_t u32[2];
uint16_t u16[4];
uint8_t u8[8];
struct
{
uint8_t n1: 4;
uint8_t n2: 4;
}u4[8];
}union_pune_t;
uint16_t foo16(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u16[1];
}
uint8_t foo8(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u8[5];
}
uint8_t foon4(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u4[9].n2;
}

What does the function insl do in Os Dev's PCI IDE tutorial?

This is the function that call's insl.
void ide_read_buffer(unsigned char channel, unsigned char reg, unsigned int buffer,
unsigned int quads) {
/* WARNING: This code contains a serious bug. The inline assembly trashes ES and
* ESP for all of the code the compiler generates between the inline
* assembly blocks.
*/
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
asm("pushw %es; movw %ds, %ax; movw %ax, %es");
if (reg < 0x08)
insl(channels[channel].base + reg - 0x00, buffer, quads);
else if (reg < 0x0C)
insl(channels[channel].base + reg - 0x06, buffer, quads);
else if (reg < 0x0E)
insl(channels[channel].ctrl + reg - 0x0A, buffer, quads);
else if (reg < 0x16)
insl(channels[channel].bmide + reg - 0x0E, buffer, quads);
asm("popw %es;");
if (reg > 0x07 && reg < 0x0C)
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
}
The link is here, https://wiki.osdev.org/PCI_IDE_Controller#Commands.
What does the function insl do in Os Dev's PCI IDE tutorial?
void ide_read_buffer(... unsigned int buffer ...)
It is clear why you don't understand the code:
unsigned int buffer is obviously a bug in the tutorial code. It should be unsigned int * buffer.
Now it is clear what insl does: It reads quad times from the port given in the first argument and writes the results to the array buffer.
The black-box behaviour of the function could be explained the following way:
void insl(unsigned reg, unsigned int *buffer, int quads)
{
int index;
for(index = 0; index < quads; index++)
{
buffer[index] = inl(reg);
}
}

Serialization: size of char and uint32_t

I have multiple questions.
Is the size of char always 1 (Byte) on every system ?
Is the size of uint32_t always 4 (Byte) on every system ?
I wrote two little functions to serialize my struct, but I can't tell if this is a good way to do it.
struct udtpackage{
char version;
bool eof;
uint32_t data_size;
uint32_t encrypted_size;
char data[BUFFERSIZE+16];
char hmac[64];
};
void serialize (udtpackage package, unsigned char* buffer){
uint32_t tmp;
memcpy(&buffer[0], &package.version, 1);
(package.eof) ? (buffer[1] = 0xFF) : (buffer[1] = 0x00);
tmp = htonl(package.data_size);
memcpy(&buffer[2], &tmp, 4);
tmp = htonl(package.encrypted_size);
memcpy(&buffer[6], &tmp, 4);
memcpy(&buffer[10], &package.data[0], BUFFERSIZE+16);
memcpy(&buffer[10+BUFFERSIZE+16], &package.hmac[0], 64);
}
void deserialize (udtpackage* package, unsigned char* buffer){
uint32_t tmp;
memcpy(&package->version, &buffer[0], 1);
(buffer[1] & 0xFF) ? (package->eof = true) : (package->eof = false);
memcpy(&tmp, &buffer[2], 4);
package->data_size = ntohl(tmp);
memcpy(&tmp, &buffer[6], 4);
package->encrypted_size = ntohl(tmp);
memcpy(&package->data[0], &buffer[10], BUFFERSIZE+16);
memcpy(&package->hmac[0], &buffer[10+BUFFERSIZE+16], 64);
}
Yes. The size of char is always 1. That doesn't mean that there are 8 bits per byte though.
No. For example, the implementation may define 32 bits per byte,
then the size of uint32_t will be 1. If this is the case, some of the fixed width types will not be defined.
Here is a potential problem:
memcpy(&buffer[2], &tmp, 4);
^
As I mentioned in the second point, the code should be:
memcpy(&buffer[2], &tmp, sizeof(tmp));
^
Going further the buffer offsets should be fixed as well, otherwise you will potentially waste memory:
memcpy(&buffer[6], &tmp, 4);
^

C code: left shift is shifting but dropping top bits

I'm doing a small embedded project where I have 40 bits transferred through a SPI type interface. I pull these bits off of a 32 bit bus and place the upper 32 bits into a uint32_t variable and the lower 8 bits into a uint8_t variable. I'm trying to combine them into a single uint64_t. However when I shift by 8, it drops the top 8 bits. Here is my code.
uint64_t getError()
{
uint32_t * disp_addr = (uint32_t*)(MYDISPLAY);
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = *(disp_addr+1);
error_upper = *(disp_addr+0);
error = ((uint64_t) error_upper) <<8 | error_lower;
return error;
}
This code is working except for the fact that it's dropping my top 8 bits.
Any thoughts or hints would be greatly appreciated. Thanks.
edit
uint64_t getError()
{
uint32_t * disp_addr = (uint32_t*)(MYDISPLAY);
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = 0x34;
error_upper = 0xABCDEF12;
error = ((uint64_t) error_upper) <<8 | error_lower;
printf("%010x", error);
//return error;
}
Results:
00cdef1234
The printf format specifier is incorrect.
#include <stdio.h>
typedef unsigned __int64 uint64_t;
typedef unsigned char uint8_t;
int main(void) {
uint64_t error_upper, error;
uint8_t error_lower;
error_lower = 0x34;
error_upper = 0xABCEDF12;
error = (error_upper << 8) | error_lower;
printf("%x\n", error);
printf("%llx\n", error);
return 0;
}
Program output:
cedf1234
abcedf1234
Why are you saying that the upper byte is cut?
If I use your code and print the result is ok:
uint32_t temp = 0x01020304;
uint32_t *disp_addr = &temp;
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = *(disp_addr+1);
error_upper = *(disp_addr+0);
error = (error_upper<<8) | error_lower;
printf("\n%08X%08X\n", (uint32_t)(error>>32), error);
Output is
0000000102030401
Are you using %d to printout the value?
Look carefully at
uint32_t *disp_addr = &temp;
...
error_lower = *(disp_addr+0);
Because disp_addr is a ptr to uint32_t you are storing a 32bit value in a 8bit variable. Depending on your machine endiannes and how you load disp_addr you may be loading the wrong data.
You probably wanted to do:
uint32_t *disp_addr = &temp;
...
error_lower = *(uint8_t *)(disp_addr+0);
which is not the same.

map variable to IOs from different ports

I'm trying to map a variable to IO from different ports. The closest example I could find is this:
union {
struct
{ // specify each bit in this char byte
unsigned bit0:1 ; // name each member and size
unsigned bit1:1 ;
unsigned bit2:1 ;
unsigned bit3:1 ;
unsigned bit4to6:3 ; // example set to 3 bits
unsigned bit7:1 ;
};
unsigned char allbits; // overall type of union
} Flag ; // name of union = Flag
Flag.allbits = 0x12; // sets value of union/bits to 0x12
Flag. bit2 = 0; // clear the if (Flag. bit2==1), etc
if (Flag. bit2 == 1) etc
Is it possible that instead having bit0, bit1, bit2 etc to have IO bits from different ports? Something like this:
union {
struct
{ // specify each bit in this char byte
LATAbits.LATA5:1 ; // name each member and size
LATAbits.LATA7:1 ;
LATBbits.LATB2:1 ;
LATBbits.LATB4:1 ;
LATBbits.LATB5:1 ;
LATCbits.LATC0:1 ;
LATCbits.LATC1:1 ;
LATCbits.LATC2:1 ;
};
unsigned char allbits; // overall type of union
} Flag ; // name of union = Flag
Flag.allbits = 0x12; // sets value of union/bits to 0x12
What's important for me is to be able to set the value of the entire union and not necessarily to access individual bits.
Well, I've found a solution. It's not the most elegant but it's working for me. If you do have other ideas and want to share, please post it.
unsigned int HoltekAddress = 0; // Variable that holds the value for union
union
{
struct
{ // Specify each bit in this char byte
unsigned int bit0 :1; // Name each member and size
unsigned int bit1 :1;
unsigned int bit2 :1;
unsigned int bit3 :1;
unsigned int bit4 :1;
unsigned int bit5 :1;
unsigned int bit6 :1;
unsigned int bit7 :1;
unsigned int bit8 :1;
unsigned int bit9 :1;
unsigned int bit10 :1;
unsigned int bit11 :1;
};
unsigned int allbits; // Union variable and name of all members
} Holtek; // Name of union = Holtek
Holtek.allbits = HoltekAddress;
LATBbits.LATB6 = Holtek.bit0;
LATBbits.LATB7 = Holtek.bit1;
LATBbits.LATB8 = Holtek.bit2;
LATBbits.LATB9 = Holtek.bit3;
LATAbits.LATA0 = Holtek.bit4;
LATAbits.LATA8 = Holtek.bit5;
LATAbits.LATA7 = Holtek.bit6;
LATDbits.LATD5 = Holtek.bit7;
LATDbits.LATD4 = Holtek.bit8;
LATDbits.LATD3 = Holtek.bit9;
LATDbits.LATD1 = Holtek.bit10;
LATDbits.LATD0 = Holtek.bit11;
Thanks everyone.
Well, this is elegant enough. The idea is that you cannot auto-magically map arbitrary bits from different "ports" into a single byte/word variable. One has to copy the value of each and every bit. The union makes it easy to pass several bits between functions.
Just my humble opinion (Teule tata).

Resources