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.
Related
I am trying to make a structure for a data packet that has a dynamic payload length and is determined by a variable within the header struct (LEN).
I am unsure on how to do this properly and I am confused by some of the examples that i have come across. Bellow is the Structure that is the basis of what i will be using.
Thanks.
struct packet
{
unsigned char payload;
unsigned int CRC : 16;
struct header
{
unsigned char SRC;
unsigned char DST;
unsigned char NS : 3; //3 bits long
unsigned char NR : 3;
unsigned char RSV : 1; //1 bit long
unsigned char LST : 1;
unsigned char OP;
unsigned char LEN;
} HEADER;
};
struct packet PACKET;
You can use a construct sometimes referred to as a "stretchy array". (Or as #Jerry Coffin points out, a "flexible array member") The variable-length payload needs to be at the end:
struct packet
{
struct header
{
unsigned char SRC;
unsigned char DST;
unsigned char NS : 3; //3 bits long
unsigned char NR : 3;
unsigned char RSV : 1; //1 bit long
unsigned char LST : 1;
unsigned char OP;
unsigned char LEN;
} HEADER;
unsigned int CRC : 16;
unsigned char payload[1]; //STRETCHY.
};
struct packet PACKET;
This type of structure needs to be dynamically allocated, since you need to manually make enough room for the payload.
PACKET * p = malloc( sizeof(PACKET)+payloadLength*sizeof(char) );
p->HEADER->LEN = payloadLength;
//fill in rest of header here.
memcpy(p->payload, incomingData, payloadLength);
Make the payload a pointer instead and allocate it at runtime according to the value of LEN in the header field.
You need to include the length in your struct but not the data. Depending on what you are doing you handle the data differently. The struct should probably contain a pointer to the data but you have to handle this when you serialize deserialize the struct. That is the pointer will mean nothing when you read it back in.
So you write the struct out including the size of the data field, then the data field out. When you read it back you fscanf the struct, then read the size of bytes the struct tells you to from the stream and store that as your data, and then finally store a pointer to the newly read data in the struct that was created with fscanf. If you are reading in multiple items like this you can continue at that point reading the next struct then data and so on.
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;
}
I am attempting to learn more about C and its arcane hidden powers, and I attempted to make a sample struct containing a pointer to a void, intended to use as array.
EDIT: Important note: This is for raw C code.
Let's say I have this struct.
typedef struct mystruct {
unsigned char foo;
unsigned int max;
enum data_t type;
void* data;
} mystruct;
I want data to hold max of either unsigned chars, unsigned short ints, and unsigned long ints, the data_t enum contains
values for those 3 cases.
enum Grid_t {gi8, gi16, gi32}; //For 8, 16 and 32 bit uints.
Then I have this function that initializes and allocates one of this structs, and is supposed to return a pointer to the new struct.
mystruct* new(unsigned char foo, unsigned int bar, long value) {
mystruct* new;
new = malloc(sizeof(mystruct)); //Allocate space for the struct.
assert(new != NULL);
new->foo = foo;
new->max = bar;
int i;
switch(type){
case gi8: default:
new->data = (unsigned char *)calloc(new->max, sizeof(unsigned char));
assert(new->data != NULL);
for(i = 0; i < new->max; i++){
*((unsigned char*)new->data + i) = (unsigned char)value;
//Can I do anything with the format new->data[n]? I can't seem
//to use the [] shortcut to point to members in this case!
}
break;
}
return new;
}
The compiler returns no warnings, but I am not too sure about this method. Is it a legitimate way to use pointers?
Is there a better way©?
I missed calling it. like mystruct* P; P = new(0,50,1024);
Unions are interesting but not what I wanted. Since I will have to approach every specific case individually anyway, casting seems as good as an union. I specifically wanted to have much larger 8-bit arrays than 32-bits arrays, so an union doesn't seem to help. For that I'd make it just an array of longs :P
No, you cannot dereference a void* pointer, it is forbidden by the C language standard. You have to cast it to a concrete pointer type before doing so.
As an alternative, depending on your needs, you can also use a union in your structure instead of a void*:
typedef struct mystruct {
unsigned char foo;
unsigned int max;
enum data_t type;
union {
unsigned char *uc;
unsigned short *us;
unsigned int *ui;
} data;
} mystruct;
At any given time, only one of data.uc, data.us, or data.ui is valid, as they all occupy the same space in memory. Then, you can use the appropriate member to get at your data array without having to cast from void*.
What about
typedef struct mystruct
{
unsigned char foo;
unsigned int max;
enum data_t type;
union
{
unsigned char *chars;
unsigned short *shortints;
unsigned long *longints;
};
} mystruct;
That way, there is no need to cast at all. Just use data_t to determine which of the pointers you want to access.
Is type supposed to be an argument to the function? (Don't name this function or any variable new or any C++ programmer who tries to use it will hunt you down)
If you want to use array indices, you can use a temporary pointer like this:
unsigned char *cdata = (unsigned char *)new->data;
cdata[i] = value;
I don't really see a problem with your approach. If you expect a particular size (which I think you do given the name gi8 etc.) I would suggest including stdint.h and using the typedefs uint8_t, uint16_t, and uint32_t.
A pointer is merely an address in the memory space. You can choose to interpret it however you wish. Review union for more information on how you can interpret the same memory location in multiple ways.
casting between pointer types is common in C and C++, and the use of void* implies that you dont want users to accidentally dereference (dereferencing a void* will cause an error, but dereferencing the same pointer when cast to int* will not)
I've run across this source in a legacy code base and I don't really know why exactly it behaves the way it does.
In the following code, the pData struct member either contains the data or a pointer to the real data in shared memory. The message is sent using IPC (msgsnd() and msgrcv()). Using the pointer casts (that are currently commented out), it fails using GCC 4.4.1 on an ARM target, the member uLen gets modified. When using memcpy() and everything works as expected. I can't really see what is wrong with the pointer casting. What is wrong here?
typedef struct {
long mtype;
unsigned short uRespQueue;
unsigned short uID;
unsigned short uLen;
unsigned char pData[8000];
} message_t;
// changing the pointer in the struct
{
unsigned char *pData = <some_pointer>;
#if 0
*((unsigned int *)pMessage->pData) = (unsigned int)pData;
#else
memcpy(pMessage->pData, &pData, sizeof(unsigned int));
#endif
}
// getting the pointer out
{
#if 0
unsigned char *pData; (unsigned char *)(*((unsigned int *)pMessage->pData));
#else
unsigned char *pData;
memcpy(&pData, pMessage->pData, sizeof(int));
#endif
}
I suspect it's an alignment problem and either GCC or the processor is trying to compensate. The structure is defined as:
typedef struct {
long mtype;
unsigned short uRespQueue;
unsigned short uID;
unsigned short uLen;
unsigned char pData[8000];
} message_t;
Assuming normal alignment restrictions and a 32-bit processor, the offsets of each field are:
mtype 0 (alignment 4)
uRespQueue 4 (alignment 2)
uID 6 (alignment 2)
uLen 8 (alignment 2)
pData 10 (alignment 1)
On all but the most recent versions of the ARM processor, memory access must be aligned on the ARM processor and with the casting:
*((unsigned int *)pMessage->pData) = (unsigned int)pData;
you are attempting to write a 32-bit value on a misaligned address. To correct the alignment, the address appears to have truncated the LSB's of the address to have the proper alignment. Doing so happened to overlap with the uLen field causing the problem.
To be able to handle this correctly, you need to make sure that you write the value to a properly aligned address. Either offset the pointer to align it or make sure pData is aligned to be able to handle 32-bit data. I would redefine the structure to align the pData member for 32-bit access.
typedef struct {
long mtype;
unsigned short uRespQueue;
unsigned short uID;
unsigned short uLen;
union { /* this will add 2-bytes of padding */
unsigned char *pData;
unsigned char rgData[8000];
};
} message_t;
The structure should still occupy the same amount of bytes since it has a 4-byte alignment due to the mtype field.
Then you should be able to access the pointer:
unsigned char *pData = ...;
/* setting the pointer */
pMessage->pData = pData;
/* getting the pointer */
pData = pMessage->pData;
That is a very nasty thing to do (the thing that's compiled out). You're trying basically to hack the code, and instead of using the data copy in the message (in the provided 8000 bytes for it), you try to put a pointer, and pass it through IPC.
The main issue is sharing memory between processes. Who knows what happens to that pointer after you send it? Who knows what happens to the data it points to? That's a very bad habbit to send out a pointer to data that is not under your control (i.e.: not protected/properly shared).
Another thing that might happen, and is probably what you're actually talking about, is the alignment. The array is of char's, the previous member in the struct is short, the compiler might attempt packing them. Recasting char[] to int * means that you take memory area and represent it as something else, without telling the compiler. You're stomping over the uLen by the cast.
memcopy is the proper way to do it.
The point here is the code "int header = (((int)(txUserPtr) - 4))"
Illustration of UserTypes and struct pointer casting is great of help!
typedef union UserTypes
{
SAUser AUser;
BUser BUser;
SCUser CUser;
SDUser DUser;
} UserTypes;
typedef struct AUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} AUser;
typedef struct AUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} AUser;
typedef struct BUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} BUser;
typedef struct CUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} CUser;
typedef struct DUser
{
int userId;
int dbIndex;
ChannelType ChanType;
} DUser;
//this is the function I want to test
void Fun(UserTypes * txUserPtr)
{
int header = (*((int*)(txUserPtr) - 4));
//the problem is here
//how should i set incoming pointer "txUserPtr" so that
//Fun() would skip following lines.
// I don't want to execute error()
if((header & 0xFF000000) != (int)0xAA000000)
{
error("sth error\n");
}
/*the following is the rest */
}
In looking for circular buffer code to reuse, I've come across a use of char which confuses me
typedef struct CircularBuffer
{
void *buffer; // data buffer
void *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
void *head; // pointer to head
void *tail; // pointer to tail
} CircularBuffer;
void cb_push_back(CircularBuffer *cb, const void *item)
{
if(cb->count == cb->capacity)
// handle error
memcpy(cb->head, item, cb->sz);
////////////// here's the part I don't understand //////////
cb->head = (char*)cb->head + cb->sz;
//////////////////////////////////////////////////////////
if(cb->head == cb->buffer_end)
cb->head = cb->buffer;
cb->count++;
}
Why cast this void pointer to a char? Is this some sort of C idiom (I have very limted C expereience)? A away convenient way to increment a pointer perhaps?
The use of a char for the position pointer comes up again in some different buffer code as well:
/**< Circular Buffer Types */
typedef unsigned char INT8U;
typedef INT8U KeyType;
typedef struct
{
INT8U writePointer; /**< write pointer */
INT8U readPointer; /**< read pointer */
INT8U size; /**< size of circular buffer */
KeyType keys[0]; /**< Element of ciruclar buffer */
} CircularBuffer;
Again, this looks like some sort of handy trick that C programmers know about, something about pointers being easy to manipulate if they're chars. But I'm really just speculating.
The cast to char * is to make pointer arithmetic perform correctly if you want to move the pointer in one-byte steps; this always works because char have, by definition, the size of 1 byte. Pointer arithmetic with void * pointers, instead, is not defined by the C standard, because void doesn't specify a size for a single item.
Another common C idiom (related to this) is to use unsigned char * when you want to access some memory as "raw bytes" (the unsigned type lets you access the unsigned value of each byte without casts); it's often used also typedefed (something along the lines of typedef unsigned char byte;) to make it extra clear that you don't want to interpret the memory as characters, but as raw bytes.
A char has a size of one byte, so it (or signed char or unsigned char) is used when you want to manipulate some region of memory simply as an array of bytes.
Void pointers just point to a value and do not have type information. So it is not possible to perform addition on void pointers. Casting it to some other type is need for pointer arithmetic. Here casting void * to char * and then adding cb->sz, Moves forward by size bytes assuming size of char is 1 .
The cast enables pointer arithmetic; without it, since cb->head is of type void*, the expression cb->head + cb->sz would have no meaning.
Once the pointer is cast to char*, the pointer addition (char*)cb->head + cb->sz means “the address of the object cb->size bytes past where cb->head points.