In my application microcontroller stm32f103 is receiving by USART fixed lenght messages, they contains gps velocity which is big endian data. But elements in structure are small endian. Is there any way without doing it manually to write it in correct way?
typedef struct {
uint32_t test1;
uint16_t test2;
}Mst;
uint8_t myArray[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
void main()
{
Mst * myStruct_p = (Mst)myArray;
}
But after that myStruct_p->test1 equals 0x030201, but should be 0x010203, and myStruct_p->test2 equals 0x0605, but should be 0x0506.
As it is ARM-Cortex M3 we can use special processor instructions. ARM CMSIS have a very handy intrinsic functions __REV & __REV16 which actually compile to the single machine code instruction.
typedef union
{
struct
{
uint32_t test1;
uint16_t test2;
};
uint8_t bytes[6];
}Mst;
Mst mst = {.bytes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }};
void main()
{
mst.test1 = __REV(mst.test1);
mst.test2 = __REV16(mst.test2);
}
Casting in that way won't work.
You can do a "deserialize" operation.
Although this might be slower than some other methods, it allows you to control the protocol better (e.g. the struct member order doesn't have to follow the protocol) And, there might be padding in the struct, which would show up if we added (e.g.) uint32_t test3; to the end of the struct.
Here's the code:
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint32_t test1;
uint16_t test2;
} Mst;
uint8_t myArray[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
uint32_t
get32(uint8_t **base)
{
uint8_t *ptr;
uint32_t val = 0;
ptr = *base;
for (int len = sizeof(uint32_t); len > 0; --len) {
val <<= 8;
val |= *ptr++;
}
*base = ptr;
return val;
}
uint16_t
get16(uint8_t **base)
{
uint8_t *ptr;
uint16_t val = 0;
ptr = *base;
for (int len = sizeof(uint16_t); len > 0; --len) {
val <<= 8;
val |= *ptr++;
}
*base = ptr;
return val;
}
int
main(void)
{
Mst myS;
uint8_t *arr = myArray;
myS.test1 = get32(&arr);
myS.test2 = get16(&arr);
printf("test1=%8.8X test2=%4.4X\n",myS.test1,myS.test2);
return 0;
}
UPDATE:
Yes guys that will work but, i would like to use the processor as little as possible. This is rather manualy putting bytes in to correct order. Also Procedure Mst * struct_p = (Mst*)myArray works safe, because while defining struct i use __attribute__((packed)), just forgoten to write this
I was going to mention/suggest packed as a possibility.
In either case you can use [under GNU]: byteswap.h to get bswap_*. Endian swapping is quite common, so these are [highly] optimized for the given arch. They can even invoke compiler intrinsics (e.g. __builtin_bswap32) which utilize any special instructions the arch has (e.g. x86 has the bswap instruction, and arm has rev16).
So, you can do [i.e. replace the for loop with] (e.g.) bswap_*:
#include <stdio.h>
#include <stdint.h>
#include <byteswap.h>
typedef struct {
uint32_t test1;
uint16_t test2;
uint32_t test3;
} __attribute__((__packed__)) Mst;
uint8_t myArray[] = {
0x01, 0x02, 0x03, 0x04,
0x05, 0x06,
0x07, 0x08, 0x09, 0x0A
};
void
getall(Mst *myS)
{
myS->test1 = bswap_32(myS->test1);
myS->test2 = bswap_16(myS->test2);
myS->test3 = bswap_32(myS->test3);
}
int
main(void)
{
Mst *myS = (Mst *) myArray;
getall(myS);
printf("test1=%8.8X test2=%4.4X test3=%8.8X\n",
myS->test1,myS->test2,myS->test3);
return 0;
}
Overlaying a struct pointer onto a byte array may not necessarily work due to alignment issues and structure padding.
The proper way would be to first use memcpy to copy over the elements:
Mst myStruct;
memcpy(&myStruct.test1, myArray, sizeof(myStruct.test1);
memcpy(&myStruct.test2, myArray + 4, sizeof(myStruct.test2);
Then use ntohs and ntohl which converts 16 and 32 bit values respectively from big endian format to the host's endianness.
myStruct.test1 = ntohl(myStruct.test1);
myStruct.test2 = ntohs(myStruct.test2);
If you just need to convert 8bit data into big endian let say data format will be in order (A B C D) and in little endian data format will be (D C B A) if final result will be stored in 32bit variable and if 16 bit variable then format will (A B) and (B A) .
So this can be done with little bit shifting technique if you know your UART data comming in which format.
Let us first assume that your UART data comes in Little endian and you want it in big endian then you can do like this.
//no structure required
uint32_t myValue;
uint16_t value;
uint8_t myArray[4] = { 0x04, 0x03, 0x02, 0x01 };
// little endian data for 32 bit
uint8_t A[2] = {0x02 ,0x01}; // little endian data for 16 bit
void main()
{
myValue = myArray[3]<<24 | myArray[2]<<16 | myArray[1]<<8 | myArray[0]; // result in big endian 32 bit value
value = A[1]<<8 | A[0]; // result in big endian 16bit value
}
Related
No matter what I do with {0,8,16,0}(16bit vector, representation for copying into a big endian 64bit value) I am unable to properly bit shift a test value of { 0x00, 0x01, (...) 0x07 };
The result I get in the debugger is always 0x0.
I tried to convert the value in a couple of different ways, but I am unable to get this right.
Executed on a little endian:
#include <mmintrin.h>
#include <stdint.h>
int main(int argc, char** argv) {
__m64 input;
__m64 vectors;
__m64 output;
_Alignas(8) uint16_t bit16Vectors[1*4] = {
0x0000,0x0008,0x0010,0x0000
// Intent: {0,8,16,0} 16 bit array
// Convert for copy: {0,16,8,0} 64bit one item
// 8bit data, Bytes need to rotate: {0,8,16,0}
};
_Alignas(8) uint8_t in[8] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};
input = _m_from_int64(*((long long*)in) );
vectors = _m_from_int64 (*((long long*)bit16Vectors));
output = _mm_sll_pi16(input, vectors);
__asm__("int3");
}
I wrote down a simple MMX-only RGB24 plane separation pseudoAssembly[which processes 8x1 values], but I am unable to convert all the 16+32bit bit shift vectors to "real world", or I do something wrong with the intrinsics.
I am unable to pin it down exactly, I just know it fails at the very first bit shift and returns the value of 0x0.
I am looking for a solution to concatenate in a array with value from defines and variable. I have already try with memcpy like that but it not working :
#define ADDRESS {0x00, 0x00, 0x00, 0x00, 0x00, 0x45}
#define SIGNATURE {0xC6, 0x54, 0x2D}
uint8_t packetCounter = 0;
uint8_t RadioData[2]={'2','1'};
uint8_t Packet = sizeof(uint8_t);
memcpy(Packet, ADDRESS, sizeof(ADDRESS));
memcpy(Packet, SIGNATURE, sizeof(SIGNATURE));
memcpy(Packet, packetCounter, sizeof(packetCounter));
memcpy(Packet, data, sizeof(data));
The goal of this code is to have an array with those value : ADDRESS+SIGNATURE+packetCounter+data. And I would like also to add "_" between each variable after.
Do you have any solution?
Thanks
It's not entirely clear what it is you want, but maybe something like this?
#include <stdint.h>
#define ADDRESS 0x00, 0x00, 0x00, 0x00, 0x00, 0x45
#define SIGNATURE 0xC6, 0x54, 0x2D
void Some_Function(void) {
uint8_t packetCounter = 0;
uint8_t RadioData[2]={'2','1'};
uint8_t Packet[] = {ADDRESS, SIGNATURE, packetCounter, RadioData[0], RadioData[1]};
}
Your problem is that Packet is an integer variable. The memcpy needs a pointer, not an integer variable. Your trying to copy a lot of bytes to a single byte location.
The quick and easy way worked fine for me. I see the exact bytes in the packet, in my debugger.
#include <vector>
#define ADDRESS {0x00, 0x00, 0x00, 0x00, 0x00, 0x45}
#define SIGNATURE {0xC6, 0x54, 0x2D}
uint8_t address[] ADDRESS;
uint8_t signature[] SIGNATURE;
uint8_t packetCounter = 0;
uint8_t RadioData[2] = { '2','1' };
int main() {
std::vector<uint8_t> packet;
std::copy(std::begin(address), std::end(address), std::back_inserter(packet));
std::copy(std::begin(signature), std::end(signature), std::back_inserter(packet));
packet.push_back(packetCounter);
std::copy(std::begin(RadioData), std::end(RadioData), std::back_inserter(packet));
// packet now has the bytes expected
return 0;
}
This is c++, although the question had both tags. I can put them in a malloc'ed area just as easily if you need C. Also the #define is completely unnecessary. I'd rather just define static const arrays.
I probably would have used unsigned char or char, possibly with a static assert if they need to be 8 bit.
I have the thankless job of writing an IPv6 header parser.
I'm wondering if the version, traffic class and flow control labels could be parsed out using bitfields.
I wrote some test code. Executing on an x86 system I get unexpected results.
#include <stdint.h>
#include <stdio.h>
typedef struct __attribute__ ((__packed__)) {
uint32_t flow_label:20;
uint32_t traffic_class:8;
uint32_t ip_version:4;
} test_t;
int main(int argc, char **argv)
{
uint8_t data[] = { 0x60, 0x00, 0x00, 0x00 };
test_t *ipv6 = (void *)data;
printf("Size is %zu, version %u, traffic class %u, flow label %u\n", sizeof(test_t), ipv6->ip_version, ipv6->traffic_class, ipv6->flow_label);
}
I'd expect the first nibble to be available in ip_version, but it doesn't seem to be, instead I get:
Size is 4, version 0, traffic class 0, flow label 96
or with the field order inverted
Size is 4, version 0, traffic class 6, flow label 0
Can anyone explain why this happens?
With bitfields, it's implementation dependent how they are laid out. You're better off declaring a 32 bit field for the start of the packet and using bit shifting to extract the relevant fields.
uint8_t ipver = data[0] >> 4;
uint8_t tclass = ((data[0] & 0xf) << 4) | (data[1] >> 4);
uint32_t flowlbl = (((uint32_t)data[1] & 0xf) << 16) | ((uint32_t)data[2] << 8) | data[3];
Indeed, even the Linux netinet/ip6.h header doesn't use a bit field for the ipv6 header:
struct ip6_hdr
{
union
{
struct ip6_hdrctl
{
uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC,
20 bits flow-ID */
uint16_t ip6_un1_plen; /* payload length */
uint8_t ip6_un1_nxt; /* next header */
uint8_t ip6_un1_hlim; /* hop limit */
} ip6_un1;
uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */
} ip6_ctlun;
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
};
I am working on a Motorola HCS08 µCU in CodeWarrior V10.6, I am trying to create an extern bitfield which has bits from existing registers. The way the bitfields are created in the µCU header is like
typedef unsigned char byte;
typedef union {
byte Byte;
struct {
byte PTAD0 :1;
byte PTAD1 :1;
byte PTAD2 :1;
byte PTAD3 :1;
byte PTAD4 :1;
byte PTAD5 :1;
byte PTAD6 :1;
byte PTAD7 :1;
} Bits;
} PTADSTR;
extern volatile PTADSTR _PTAD #0x00000000;
#define PTAD _PTAD.Byte
#define PTAD_PTAD0 _PTAD.Bits.PTAD0
#define PTAD_PTAD1 _PTAD.Bits.PTAD1
#define PTAD_PTAD2 _PTAD.Bits.PTAD2
#define PTAD_PTAD3 _PTAD.Bits.PTAD3
#define PTAD_PTAD4 _PTAD.Bits.PTAD4
#define PTAD_PTAD5 _PTAD.Bits.PTAD5
#define PTAD_PTAD6 _PTAD.Bits.PTAD6
#define PTAD_PTAD7 _PTAD.Bits.PTAD7
Which will let the register value be changed either by PTAD = 0x01, or PTAD_PTAD0 = 1, for example. This definition is basically the same for PTAD, PTBD, PTCD, ... PTGD, the only thing changing is the address.
My attemp to create a custom bitfield out of the previous existing variables is
typedef union {
byte Byte;
struct {
byte *DB0;
byte *DB1;
byte *DB2;
byte *DB3;
byte *DB4;
byte *DB5;
byte *DB6;
byte *DB7;
} Bits;
} LCDDSTR;
I would create and initialize the bitfield as LCDDSTR lcd = {{&PTGD_PTGD6, &PTBD_PTBD5, ...}}, because by some reason, the initialization like LCDSTR lcd = {*.Bits.DB0 = &PTGD_PTGD6, *.Bits.DB1 = &PTBD_PTBD5, ...} (treating it as a struct, please correct me again) advice in How to initialize a struct in accordance with C programming language standards does not work with this compiler (it does work on an online compiler).
However, as you may see I am sort of grouping the bits, and (if it would work) I would be able to change the values of the actual register by doing *lcd.Bits.DB0 = 1, or something like that, but if I do lcd.Byte = 0x00, I would be changing the last (I think) byte of the memory address contained in lcd.Bits.DB0, you know, because the struct doesn't actually contains the data, but the pointers instead.
How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other, which I guess would make it easier). Is it even possible? I hope it is.
How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other..
I don't think you can do it with a struct. That is because bitfields by definition have to occupy the same or contiguous addresses.
However macros may be useful here
#define DB0 PTGD_PTGD6
#define DB1 PTBD_PTBD5
....
And to clear the bits to all 0's or set to all 1's you can use a multiline macro
#define SET_DB(x) do { \
PTGD_PTGD6 = x; \
PTBD_PTBD5 = x; \
...... \
} while(0)
How would I go on achieving a struct that is able to contain and modify bits from several registers?
You can't.
A structure must represent a single, continuous block of memory -- otherwise, operations like taking the sizeof the structure, or performing operations on a pointer to one would make no sense.
If you want to permute the bits of a value, you will need to find some way of doing so explicitly. If the order of your bits is relatively simple, this may be possible with a few bitwise operations; if it's weirder, you may need to use a lookup table.
Beyond that: bitfields in C are pretty limited. The language does not make a lot of guarantees about how a structure containing bitfields will end up laid out in memory; they are generally best avoided for portable code. (Which doesn't apply here, as you're writing code for a specific compiler/microcontroller combination, but it's worth keeping in mind in general.)
Your union does unfortunately not make any sense, because it forms a union of one byte and 8 byte*. Since a pointer is 16 bit on HCS08, this ends up as 8*2 = 16 bytes of data, which can't be used in any meaningful way.
Please note that the C structure called bit-fields is very poorly specified by the standard and therefore should be avoided in any program. See this.
Please note that the Codewarrior register maps aren't remotely close to following the C standard (nor MISRA-C).
Please note that structs in general are problematic for hardware register mapping, since structs can contain padding. You don't have that problem on HCS08 specifically, since it doesn't require alignment of data. But most MCUs do require that.
It is therefore better to roll out your own register map in standard C if you have that option. The port A data register could simply be defined like this:
#define PTAD (*(volatile uint8_t*)0x0000U)
#define PTAD7 (1U << 7)
#define PTAD6 (1U << 6)
#define PTAD5 (1U << 5)
#define PTAD4 (1U << 4)
#define PTAD3 (1U << 3)
#define PTAD2 (1U << 2)
#define PTAD1 (1U << 1)
#define PTAD0 (1U << 0)
As we can tell, defining the bit masks is mostly superfluous anyway, as PTAD |= 1 << 7; is equally readable to PTAD |= PTAD7;. This is because this was a pure I/O port. Defining textual bit masks for status and control registers on the other hand, increases the readability of the code significantly.
If you want to modify bits from several registers, you'd do something like the following:
Assume we have a RGB (red-green-blue) LED, common cathode, with 3 colors connected to 3 different pins on 3 different ports. Instead of beating up the PCB designer, you could do this:
#define RGB_RED_PTD PTAD
#define RGB_RED_PTDD PTADD
...
#define RGB_BLUE_PTD PTBD
#define RGB_BLUE_PTDD PTBDD
...
#define RGB_GREEN_PTD PTDD
#define RGB_GREEN PTDD PTDDD
#define RGB_RED_PIN 1
#define RGB_BLUE_PIN 5
#define RGB_GREEN_PIN 3
You can now set these independently of where they happen to be located on the hardware:
void rgb_init (void)
{
RGB_RED_PTDD |= (1 << RGB_RED_PIN);
RGB_BLUE_PTDD |= (1 << RGB_BLUE_PIN);
RGB_GREEN_PTDD |= (1 << RGB_GREEN_PIN);
}
void rgb_yellow (void)
{
RGB_RED_PTD |= (1 << RGB_RED_PIN);
RGB_BLUE_PTD &= ~(1 << RGB_BLUE_PIN);
RGB_GREEN_PTD |= (1 << RGB_GREEN_PIN);
}
And so on. Examples were for HCS08 but the same can of course be used universally on any MCU with direct port I/O.
It sounds like an approach such as the following is along the lines of where you would like to go with a solution.
I have not tested this as I do not have the hardware however this should provide an alternative to look at.
This assumes that you want to turn on particular pins or turn off particular pins but there will not be a case where you will want to turn on some pins and turn off other pins for a particular device in a single operation. If that should be the case I would consider making the type of RegPinNo be an unsigned short to include an op code for each register/pin number combination.
This also assumes that timing of operations is not a critical constraint and that the hardware has sufficient horsepower such that small loops are not much of a burden on throughput and hogging CPU time needed for other things. So this code may need changes to improve optimization if that is a consideration.
I assume that you want some kind of a easily readable way of expressing a command that will turn on and off a series of bits scattered across several areas of memory.
The first thing is to come up with a representation of what such a command would look like and it seems to me that borrowing from a char array to represent a string would suffice.
typedef byte RegPinNo; // upper nibble indicates register number 0 - 7, lower nibble indicates pin number 0 - 7
const byte REGPINNOEOS = 0xff; // the end of string for a RegPinNo array.
And these would be used to define an array of register/pin numbers as in the following.
RegPinNo myLed[] = { 0x01, 0x12, REGPINNOEOS }; // LED is addressed through Register 0, Pin 0 and Register 1, Pin 1 (zero based)
So at this point we have a way to describe that a particular device, an LED in this case, is addressed through a series of register/pin number items.
Next lets create a small library of functions that will use this representation to actually modify the specific pins in specific registers by traversing this array of register/pin numbers and performing an operation on it such as setting the bit in the register or clearing the bit in the register.
typedef unsigned char byte;
typedef union {
byte Byte;
struct {
byte PTAD0 : 1;
byte PTAD1 : 1;
byte PTAD2 : 1;
byte PTAD3 : 1;
byte PTAD4 : 1;
byte PTAD5 : 1;
byte PTAD6 : 1;
byte PTAD7 : 1;
} Bits;
} PTADSTR;
// Define a pointer to the beginning of the register area. This area is composed of
// 8 different registers each of which is one byte in size.
// We will address these registers as Register 0, Register 1, ... Register 7 which just happens
// to be how C does its zero based indexing.
// The bits representing pins on the PCB we will address as Pin 0, Pin 1, ... Pin 7.
extern volatile PTADSTR (* const _PTAD) = 0x00000000;
void SetRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte |= pins[bPinNo];
}
}
void ClearRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte &= ~pins[bPinNo];
}
}
void ToggleRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte ^= pins[bPinNo];
}
}
You would use the above something like the following. Not sure what a time delay function would look like in your environment so I am using a function Sleep() which takes an argument as to the number of milliseconds to delay or sleep.
void LightLed (int nMilliSeconds)
{
RegPinNo myLed[] = { 0x01, 0x12, REGPINNOEOS }; // LED is addressed through Register 0, Pin 0 and Register 1, Pin 1 (zero based)
SetRegPins(myLed); // turn on the LED
Sleep(nMilliSeconds); // delay for a time with the LED lit
ClearRegPins(myLed); // turn the LED back off
}
Edit - A Refinement
A more efficient implementation that would allow multiple pins to be set in a particular register at the same time would be to define the use of RegPinNo as being an unsigned short` with the upper byte being the register number and the lower byte being the pins to manipulate as a bit mask for the byte.
With this approach you would have a SetRegPins() function that would look like the following. A similar change would be needed for the other functions.
void SetRegPins(RegPinNo *x)
{
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 8) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0xFF; // get the pin mask
_PTAD[bRegNo].Byte |= bPinNo;
}
}
And the typedefs would look like:
typedef unsigned short RegPinNo; // upper byte indicates register number 0 - 7, lower byte provides pin mask
const byte REGPINNOEOS = 0xffff; // the end of string for a RegPinNo array.
And these elements would be used like:
void LightLed (int nMilliSeconds)
{
RegPinNo myLed[] = { 0x0002, 0x0103, REGPINNOEOS }; // LED is addressed through Register 0, Pin 1 and Register 1, Pin 0 and Pin 1 (zero based)
SetRegPins(myLed); // turn on the LED
Sleep(nMilliSeconds); // delay for a time with the LED lit
ClearRegPins(myLed); // turn the LED back off
}
I have a unsigned 64-bit word and a bit padded structure which are both given below.The structure is inside a union which contains several(11 to be exact) similar but slightly structures.
uint64_t final_data_word;
#pragma pack(1)
typedef struct control_block_format_1_s
{
uint8_t block_type_field:8;
uint8_t control_word_0:7;
uint8_t control_word_1:7;
uint8_t control_word_2:7;
uint8_t control_word_3:7;
uint8_t control_word_4:7;
uint8_t control_word_5:7;
uint8_t control_word_6:7;
uint8_t control_word_7:7;
}control_block_format_1_t;
typedef union
{
control_block_format_1_t *cb_1;
control_block_format_2_t *cb_2;
control_block_format_3_t *cb_3;
control_block_format_4_t *cb_4;
control_block_format_5_t *cb_5;
control_block_format_6_t *cb_6;
control_block_format_7_t *cb_7;
control_block_format_8_t *cb_8;
control_block_format_9_t *cb_9;
control_block_format_10_t *cb_10;
control_block_format_11_t *cb_11;
}block_payload_union_t;
#pragma pack()
I want to interpret the 64 bits in the 64-bit word as fields in the structure.so I am doing the below operation
block_payload_union_t *block_pload =(block_payload_union_t*)malloc(sizeof(block_payload_union_t*));
block_pload->cb_1 = (control_block_format_1_t*)(&final_data_word);
but I am not getting the expected values for the last field in my structure.Can anyone see any problem with what I am doing?Any suggestions or comments are appreciated.
#Jonathan
I have added the following comments to my code.
printf("sizeof(union) = %zu\n", sizeof(block_payload_union_t));
printf("sizeof(cb1) = %zu\n", sizeof(control_block_format_1_t));
printf("FDW = 0x%.16lx\n", final_data_word);
//printf("*bp->llp = 0x%.16lx\n", *block_pload->llp);
printf("bp->cb1->block_type_fld = 0x%.2X\n", block_pload->cb_1->block_type_field);
printf("bp->cb1->control_word_0 = 0x%.2X\n", block_pload->cb_1->control_word_0);
printf("bp->cb1->control_word_1 = 0x%.2X\n", block_pload->cb_1->control_word_1);
printf("bp->cb1->control_word_2 = 0x%.2X\n", block_pload->cb_1->control_word_2);
printf("bp->cb1->control_word_3 = 0x%.2X\n", block_pload->cb_1->control_word_3);
printf("bp->cb1->control_word_4 = 0x%.2X\n", block_pload->cb_1->control_word_4);
printf("bp->cb1->control_word_5 = 0x%.2X\n", block_pload->cb_1->control_word_5);
printf("bp->cb1->control_word_6 = 0x%.2X\n", block_pload->cb_1->control_word_6);
printf("bp->cb1->control_word_7 = 0x%.2X\n", block_pload->cb_1->control_word_7);
The output I got without #pragma pack() was as follows
final data word 0x1e00000000000000
sizeof(union) = 8
sizeof(cb1) = 9
FDW = 0x1e00000000000000
bp->cb1->block_type_fld = 0x00
bp->cb1->control_word_0 = 0x00
bp->cb1->control_word_1 = 0x00
bp->cb1->control_word_2 = 0x00
bp->cb1->control_word_3 = 0x00
bp->cb1->control_word_4 = 0x00
bp->cb1->control_word_5 = 0x00
bp->cb1->control_word_6 = 0x1E
bp->cb1->control_word_7 = 0x78
The output with #pragma pack() was as follows
final data word 0x1e00000000000000
sizeof(union) = 8
sizeof(cb1) = 8
FDW = 0x1e00000000000000
bp->cb1->block_type_fld = 0x00
bp->cb1->control_word_0 = 0x00
bp->cb1->control_word_1 = 0x00
bp->cb1->control_word_2 = 0x00
bp->cb1->control_word_3 = 0x00
bp->cb1->control_word_4 = 0x00
bp->cb1->control_word_5 = 0x00
bp->cb1->control_word_6 = 0x00
bp->cb1->control_word_7 = 0x0F
which is similar to the output you got on Jonathan's machine.
You should be using sizeof(block_payload_union_t) instead of sizeof(block_payload_union_t *) in the call to malloc(). However, on a 64-bit machine, it probably gives you the same size (8), so you get away with it, for all it is wrong.
It is slightly odd that your block_payload_union_t contains pointers to your field layouts instead of holding the actual values.
You have not shown us the declaration of final_data_word. Have you checked the size of your union versus the size you expect?
On a Mac running Lion (10.7.2), I get this output from the program which follows:
Output
With #pragma pack(1):
sizeof(union) = 8
sizeof(cb1) = 8
FDW = 0xFEDCBA9876543210
*bp->llp = 0xFEDCBA9876543210
bp->cb1->block_type_fld = 0x10
bp->cb1->control_word_0 = 0x32
bp->cb1->control_word_1 = 0x28
bp->cb1->control_word_2 = 0x59
bp->cb1->control_word_3 = 0x43
bp->cb1->control_word_4 = 0x29
bp->cb1->control_word_5 = 0x17
bp->cb1->control_word_6 = 0x37
bp->cb1->control_word_7 = 0x7F
Without #pragma pack(1):
sizeof(union) = 8
sizeof(cb1) = 9
FDW = 0xFEDCBA9876543210
*bp->llp = 0xFEDCBA9876543210
bp->cb1->block_type_fld = 0x10
bp->cb1->control_word_0 = 0x32
bp->cb1->control_word_1 = 0x54
bp->cb1->control_word_2 = 0x76
bp->cb1->control_word_3 = 0x18
bp->cb1->control_word_4 = 0x3A
bp->cb1->control_word_5 = 0x5C
bp->cb1->control_word_6 = 0x7E
bp->cb1->control_word_7 = 0x10
What are you getting?
Program
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#pragma pack(1)
typedef struct control_block_format_1_s
{
uint8_t block_type_field:8;
uint8_t control_word_0:7;
uint8_t control_word_1:7;
uint8_t control_word_2:7;
uint8_t control_word_3:7;
uint8_t control_word_4:7;
uint8_t control_word_5:7;
uint8_t control_word_6:7;
uint8_t control_word_7:7;
} control_block_format_1_t;
typedef union
{
long long *llp;
control_block_format_1_t *cb_1;
//control_block_format_2_t *cb_2;
//control_block_format_3_t *cb_3;
//control_block_format_4_t *cb_4;
//control_block_format_5_t *cb_5;
//control_block_format_6_t *cb_6;
//control_block_format_7_t *cb_7;
//control_block_format_8_t *cb_8;
//control_block_format_9_t *cb_9;
//control_block_format_10_t *cb_10;
//control_block_format_11_t *cb_11;
} block_payload_union_t;
#pragma pack()
int main(void)
{
long long final_data_word = 0xFEDCBA9876543210;
block_payload_union_t *block_pload =(block_payload_union_t*)malloc(sizeof(block_payload_union_t));
block_pload->cb_1 = (control_block_format_1_t*)(&final_data_word);
printf("sizeof(union) = %zu\n", sizeof(block_payload_union_t));
printf("sizeof(cb1) = %zu\n", sizeof(control_block_format_1_t));
printf("FDW = 0x%.16llX\n", final_data_word);
printf("*bp->llp = 0x%.16llX\n", *block_pload->llp);
printf("bp->cb1->block_type_fld = 0x%.2X\n", block_pload->cb_1->block_type_field);
printf("bp->cb1->control_word_0 = 0x%.2X\n", block_pload->cb_1->control_word_0);
printf("bp->cb1->control_word_1 = 0x%.2X\n", block_pload->cb_1->control_word_1);
printf("bp->cb1->control_word_2 = 0x%.2X\n", block_pload->cb_1->control_word_2);
printf("bp->cb1->control_word_3 = 0x%.2X\n", block_pload->cb_1->control_word_3);
printf("bp->cb1->control_word_4 = 0x%.2X\n", block_pload->cb_1->control_word_4);
printf("bp->cb1->control_word_5 = 0x%.2X\n", block_pload->cb_1->control_word_5);
printf("bp->cb1->control_word_6 = 0x%.2X\n", block_pload->cb_1->control_word_6);
printf("bp->cb1->control_word_7 = 0x%.2X\n", block_pload->cb_1->control_word_7);
return(0);
}
What's the point in having pointers as members in your union? You could achieve the same result via casts.
If what you want is to access the data (and not the pointers) through the eleven different structures, then in the union you don't want to use pointers but the structs directly:
typedef union
{
control_block_format_1_t cb_1;
control_block_format_2_t cb_2;
control_block_format_3_t cb_3;
control_block_format_4_t cb_4;
control_block_format_5_t cb_5;
control_block_format_6_t cb_6;
control_block_format_7_t cb_7;
control_block_format_8_t cb_8;
control_block_format_9_t cb_9;
control_block_format_10_t cb_10;
control_block_format_11_t cb_11;
} block_payload_union_t;
Now the size of your block_payload_union_t struct is just 64-bits, and you can work with this data using any of the eleven versions.
#pragma pack(1) directive would cause that member to be packed in the structure on a 1-byte boundary, however #pragma pack directive aligns all bit fields in a structure/union on 1-bit boundaries. This is why the last field is kicked off. Check the sizeof of control_block_format_1_s whether it is 8 or 9.