C Copy char to struct - c

I read a bunch of input(sensors) where I get 0(off) or 1(on) for every sensor. These values I get in a char* where I have the result for all sensors. 1 bit for every sensor.
When I want to use these values in my code I don't feel like it is a good idea to AND this result with another char with the one bit set which i'm interested in since the code gets very bloated then.
Instead i was thinking of to make a struct like this one:
struct sensors {
unsigned int Sensor0:1;
unsigned int Sensor1:1;
unsigned int Sensor2:1;
unsigned int Sensor3:1;
unsigned int Sensor4:1;
unsigned int Sensor5:1;
unsigned int Sensor6:1;
unsigned int Sensor7:1;
}
struct sensors s1;
memcpy(buf, (char*)&sensors, 1);
But from what I've read a struct might not save every component after each other in memory and might insert padding and other stuff in between which makes this a no go.
Am I wrong about this? Are there any better ways to do this?

With your current definition of struct sensors, the compiler will insert additional padding because int has alignment requirements, usually on a sizeof(int) boundary. Moreover, int must be wider than char, hence it can accommodate more than 8 flags, which you're not gonna need.
If you declare it like this (use unsigned char instead), there should be no padding because char has the least strict alignment requirements:
struct sensors {
unsigned char Sensor0:1;
unsigned char Sensor1:1;
unsigned char Sensor2:1;
unsigned char Sensor3:1;
unsigned char Sensor4:1;
unsigned char Sensor5:1;
unsigned char Sensor6:1;
unsigned char Sensor7:1;
}
This might not work only on a very strange platform where CHAR_BIT != 8.

To add to Blagovest's answer:
A bit-field approach seems sound. However, you'll have to instruct your compiler to not introduce a padding between the fields. For GCC, this is done by putting __attribute__ ((packed)) after the definition of a structure, like this:
struct sensors {
unsigned char Sensor0:1;
unsigned char Sensor1:1;
unsigned char Sensor2:1;
unsigned char Sensor3:1;
unsigned char Sensor4:1;
unsigned char Sensor5:1;
unsigned char Sensor6:1;
unsigned char Sensor7:1;
} __attribute__ ((packed));
Note that GCC before 4.4 used to introduce padding for char fields irrespective of this directive; see the documentation on warning option -Wpacked-bitfield-compat for more information.

If you want to be super-safe, you can AND with a character that has one bit set. You probably would want to do this with an array, instead of a struct. You can wrap it into a nice loop, and it's not much work at all.
However, any sane C compiler will put unsigned integers in contiguous memory, so it should be safe to do some kind of copy like that. The compiler usually only puts in extra padding when there are types of different sizes. Unfortunately I do not know if this will work easily for you because you have the command memcpy(buf, (char*)&sensors, 1) will copy your byte of sensor data in the first integer - which is not what you want.

Instead of memcpy(), I would use a union to access the data as defined in Blagovest Buyukliev answer:
union combSensors {
unsigned char all_fields;
struct sensors field_by_field;
}

Related

union and structure memory sharing

I was trying to find the answer of a question which involves two structures inside a union.
I have typed the question in online debugger the answer which I am finding and the real answer is not giving hands to each other. Can somebody help me out with the answer with explanation.
#include <stdio.h>
int main()
{
union{
struct{
char c[2];
char ch[2];
}s;
struct {
short int i;
short int j;
}st;
}u={12,1,15,1};
printf("%d%d",u.st.i,u.st.j);
}
answer is 268 and 271
Decimal numbers are not very good for this kind of tests. You should also enable all warnings as well. If you do so you will get
<source>:25:8: warning: missing braces around initializer [-Wmissing-braces]
So let's rewrite your program a little bit:
int main()
{
union
{
struct
{
char c[2];
char ch[2];
}s;
struct
{
short int i;
short int j;
}st;
}u={.s = {{0x12,0x01},{0x15,0x01}}}; //better to show compiler what you want to initialize
printf("%04hx %04hx",u.st.i,u.st.j);
}
And the result is:
0112 0115
clearly showing the numbers we have used in the initialization. The numbers show us that this system uses little endian system where the least significant byte is placed first.
You should be avare that compiler is free to add any padding needed. To avoid it you have to use compiler extensions - structure packing.
Start by making more sense of this by swapping to hexadecimal: {0xC,0x1,0xF,0x1}. This allows us to view the bytes as they are stored in memory, without worrying about converting to/from decimal base.
When initializing a union, the first member gets initialized, in this case the struct s.
It would be cleaner to write { {{0xC,0x1}, {0xF,0x1}} } but unfortunately C allows omitting the curly braces of inner structs/arrays, allowing us to put sloppily written crap in our initialization lists just because we can.
The memory order of a char byte array is always top to bottom on any system: first byte on least significant address. That is: 0xC 0x1 0xF 0x1.
Strictly speaking, the compiler is free to add struct padding bytes anywhere between the struct/union members, to compensate for misalignment. Doesn't happen in this specific case, but it would happen if we for example used char c[3].
When you "type pun" this memory area using shorts, they get read according to endianess, since short is larger than 1 byte and an integer type.
On a little endian CPU you would therefore get each short to assume that 0xC is the least significant byte and so the first short ends up as 010C hex.
If we translate your code to hex, it should be clearer:
#include <stdio.h>
int main()
{
union{
struct{
char c[2];
char ch[2];
}s;
struct {
short int i;
short int j;
}st;
}u={ {{0xC,0x1}, {0xF,0x1}} };
printf("%.4X\n%.4X",u.st.i,u.st.j);
}
Output on little endian CPU:
010C
010F
10Ch = 268d and so on.

Regarding a Specific C Variable

It is a simple question, what does this set SrcPkt to?
extern PacketStruct RxPacket[NUM_PACKETS], TxPacket[NUM_PACKETS];
extern IPMBPacketRequestStruc *SrcPkt;
SrcPkt = (IPMBPacketRequestStruc *)&(RxPacket[i].packetdata[0]);
I have a solid understanding of C and C++ but pointers have always been my weak point.
This line of code seems to set the pointer SrcPkt to point to the reference of RxPacket[i].packetdata[0]
I am only partly confident with what I believe is the correct answer, I just want some validation.
EDIT:
typedef struct
{
unsigned char status; // Buffer status
unsigned char stat2; // re-send status
unsigned char channel; // Channel source/destination
unsigned char length; // Total # of bytes in packetdata
unsigned char index; // Current byte being processed in packetdata
unsigned char packetdata[IPMB_MAXDATALENGTH];
} PacketStruct;
typedef struct
{
unsigned char rsSA;
unsigned char netFNrsLUN;
unsigned char cksm1;
unsigned char rqSA;
unsigned char rqSEQrqLUN;
unsigned char cmd;
unsigned char pktdta[37]; // rest of packet data
} IPMBPacketRequestStruc;
This sets SrcPkt to point to the address of RxPacket[i].packetdata[0]. The & operator returns the address of (a pointer to) the packet data, which is cast to the same type as SrcPkt and assigned to the SrcPkt pointer variable.
References, as exist in C++, do not exist in C. In C++, they are usually implemented as syntactic sugar around pointers so that you can use the objects they point to without having to manually dereference them. In C, you must handle and dereference pointers yourself.

How to add an array to a bitfield struct?

I tried to use bit fields in a struct for some values which only need one or two bits instead of a whole byte.
My code is:
struct s_rdata {
signed int p0:28;
signed int p1:28;
signed int p2:28;
unsigned int d0:17;
unsigned int d1:17;
unsigned int d2:17;
unsigned char data1:1;
unsigned char data2:1;
} rdata;
So, you might see that there are variables named p0 - p2, d0 - d2 and data1 - data2.
I'd now like to have those in an array. However, none of this lines does work:
signed int p[3]:28;
signed int p:28[3];
Can't I add an array to a bitfield list, an array of signed int only needing 28 bits per entry?
No, you cannot have an array of bitfields, nor a bitfield whose base type is an array type. The latter doesn't even make sense. The former would be counter-productive, as you would lose any space efficiency gained by using bitfields in the first place.
You can have an array of a structs with a single bitfield member:
struct container {
signed int bitfield:7;
} array[3];
but again, you would lose any space efficiency associated with the bitfield use.
You can create an array of any struct type, of course, including those with multiple bitfield members. In that case, you may achieve some internal space efficiency within the individual structures, but you will likely see padding at the end of each one that reduces the overall space efficiency of the array.
Ultimately, unless your program's memory consumption is excessive for its target environment, I strongly recommend that you forget about bitfields. They will complicate your life for an uncertain gain of uncertain importance, and that gain will likely be offset by a performance degradation (of uncertain magnitude and importance).
Should you eventually decide that the program really is using too much memory, then be certain to test any change you make to see how much improvement it yields, and at what cost.
I agree with #John's assessment with respect to space inefficiencies, but that notwithstanding, here is an idea to contain contents of a bit field within struct array:
typedef struct
{
int A : 16;
int B : 16;
} Struct1;
typedef struct
{
Struct1 B;//bitfield struct
int array[10];//combined with array (of any legal type)
}
Here is an example of populating array with contents of bit struct:
typedef struct {
signed int p0:28;
signed int p1:28;
signed int p2:28;
unsigned int d0:17;
unsigned int d1:17;
unsigned int d2:17;
unsigned char data1:1;
unsigned char data2:1;
} RDATA;
typedef struct {
int A[3];
unsigned int B[3];
unsigned char C[2];
} ARRAY;
RDATA rdata = {//initialize instance of RDATA with data
28,
28,
28,
17,
17,
17,
1,
1
};
int WriteToArray(ARRAY *a);
int main(void)
{
ARRAY a;
WriteToArray(&a);//populate array with RDATA values
//ARRAY is now populated with bitfield values;
a.A[0];
a.A[1];
//and so on
return 0;
}
WriteToArray(ARRAY *a)
{
a->A[0]=rdata.p0;//using values initialized above
a->A[1]=rdata.p1;
a->A[2]=rdata.p2;
a->B[0]=rdata.d0;
a->B[1]=rdata.d1;
a->B[2]=rdata.d2;
a->C[0]=rdata.data1;
a->C[1]=rdata.data2;
return 0;
}
You can also experiment with pragma pack statements to look at effects on space, but refer to #John's comment under your post for additional considerations regarding pragma and spacing.

How to address all fields in a struct like these registers?

If you've programmed a microcontroller, you're probably familiar with manipulating select bits of a given register, or writing a byte to the whole thing. On a PIC using C for example, I can write an entire byte to PORTA to set all the bits, or I can simply address PORTAbits.RA# to set a single bit. I'm trying to mimic the way these structs/unions are defined so I can do the same thing with a variable in my program. Specifically, when the microcontroller turns on I want to be able to reset a register I myself have defined with something like
REGISTER = 0;
versus
REGISTERbits.BIT0 = 0;
REGISTERbits.BIT1 = 0;
...
//or
REGISTERbits = (0,0,0,0,0,0,0,0);
etc.
Obviously the former is more elegant and saves a lot of line space. The header file of the microcontroller does it like this:
#ifndef __18F2550_H
#define __18F2550_H
....
extern volatile near unsigned char LATA;
extern volatile near struct {
unsigned LATA0:1;
unsigned LATA1:1;
unsigned LATA2:1;
unsigned LATA3:1;
unsigned LATA4:1;
unsigned LATA5:1;
unsigned LATA6:1;
} LATAbits;
...for each and every register, and registers with multiple bytes use unions of structs for their Registerbits. Since my initialization/declaration is in the main source file and not a header, I've dropped the extern and near off mine:
volatile unsigned char InReg;
volatile struct{
unsigned NSENS:1; //One magnetic sensor per direction
unsigned SSENS:1;
unsigned ESENS:1;
unsigned WSENS:1;
unsigned YBTN:1; //One crosswalk button input per axis
unsigned XBTN:1; //(4 buttons tied together each)
unsigned :2;
} InRegbits;
...but on compile, InReg and InRegbits are defined as two separate locations in memory, which means I can't write to InReg to change InRegbits. How do I change this so that it works? Does the one I'm trying to copy only work because it's a special microcontroller register?
Thanks for any help
volatile union InReg {
unsigned char InRegAll;
struct near {
unsigned NSENS:1; //One magnetic sensor per direction
unsigned SSENS:1;
unsigned ESENS:1;
unsigned WSENS:1;
unsigned YBTN:1; //One crosswalk button input per axis
unsigned XBTN:1; //(4 buttons tied together each)
unsigned :2;
} InRegbits;
}
Be aware that this code may not be portable.
To guarantee the same result, you'll need to have two structs within a union. The standard says that if the members of a union are structs, where the first struct member types are compatible (and relate to the same bitwidth), you can operate on any of them as the same. Otherwise accessing any union member via another is undefined behaviour.
e.g.
volatile union {
volatile struct {
unsigned int InReg;
} InReg;
volatile struct {
unsigned NSENS:1; //One magnetic sensor per direction
unsigned SSENS:1;
unsigned ESENS:1;
unsigned WSENS:1;
unsigned YBTN:1; //One crosswalk button input per axis
unsigned XBTN:1; //(4 buttons tied together each)
unsigned:2;
} InRegbits;
} Reg_s;

Union/Structure datatype and bit field referencing speed

Using the following union typedef, is there a difference in speed between accessing MyPacket.Byte.LB compared with MyPacket.Field.LB?
typedef union // create a union to assemble bytes into ints
{
int Packet; // contains an int
struct
{
char HB;
char LB;
}Byte;
struct
{
unsigned field1:4;
unsigned field2:2;
unsigned field3:1;
unsigned field4:1;
unsigned LB:8;
}Field;
} packetunion;
packetunion MyPacket;
The only way to know for sure is to code up both versions and profile them on the target system, for multiple compiler optimization settings. I'd be genuinely surprised if you saw a measurable difference.

Resources