Is there a clean way of casting a struct into an uint64_t or any other int, given that struct in <= to the sizeof int?
The only thing I can think of is only an 'ok' solution - to use unions. However I have never been fond of them.
Let me add a code snippet to clarify:
typedef struct {
uint8_t field: 5;
uint8_t field2: 4;
/* and so on... */
}some_struct_t;
some_struct_t some_struct;
//init struct here
uint32_t register;
Now how do i cast some_struct to capture its bits order in uint32_t register.
Hope that makes it a bit clearer.
I've just hit the same problem, and I solved it with a union like this:
typedef union {
struct {
uint8_t field: 5;
uint8_t field2: 4;
/* and so on... */
} fields;
uint32_t bits;
} some_struct_t;
/* cast from uint32_t x */
some_struct_t mystruct = { .bits = x };
/* cast to uint32_t */
uint32_t x = mystruct.bits;
HTH,
Alex
A non-portable solution:
struct smallst {
int a;
char b;
};
void make_uint64_t(struct smallst *ps, uint64_t *pi) {
memcpy(pi, ps, sizeof(struct smallst));
}
You may face problems if you, for example, pack the struct on a little-endian machine and unpack it on a big-endian machine.
you can use pointers and it will be easy
for example:
struct s {
int a:8;
int b:4;
int c:4;
int d:8;
int e:8; }* st;
st->b = 0x8;
st->c = 1;
int *struct_as_int = st;
hope it helps
You can cast object's pointer to desired type and then resolve it. I assume it can be a little bit slower than using unions or something else. But this does not require additional actions and can be used in place.
Short answer:
*(uint16_t *)&my_struct
Example:
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint8_t field1;
uint8_t field2;
} MyStruct;
int main() {
MyStruct my_struct = {0xFA, 0x7D};
uint16_t num_my_struct = *(uint16_t *)&my_struct;
printf("%X \n", num_my_struct); // 7DFA
return 0;
}
Related
Payload_Manager.h
typedef struct ATEIS_Payload_s* pATEIS_Payload;
Payload_Manager.c
#include "Payload_Manager.h"
struct __attribute__((__packed__))ATEIS_Payload_s //payload
{
uint32_t Addr;
uint16_t Cmd;
uint16_t Len;
uint8_t Data[];
};
DNM_Manager.h
#include "Payload_Manager.h"
typedef struct DNM_s* pDNM;
pDNM DNMManager_Ctor(pDNM this, pATEIS_Payload src);
DNM_Manager.c
#include "Payload_Manager.h"
struct DNM_s
{
uint32_t Addr;
uint32_t SerialNo;
uint32_t SubnetMask;
uint16_t Tick;
uint8_t Name[NAME_SIZE];
}DNMSet[SET_SIZE], DNMTemp;
pDNM DNMManager_Ctor(pDNM this, pATEIS_Payload src)
{
memcpy(this->Name, &src->Data[NAME], NAME_SIZE); //ptr to incomplete class type is not allowed
this->Addr = src->Addr; //ditto
this->SerialNo = *(uint32_t*)&src->Data[SN]; //ditto
this->SubnetMask = *(uint32_t*)&src->Data[SUBMASK]; //ditto
this->Tick = 0;
return this;
}
main.c
#include "Payload_Manager.h"
#include "DNM_Manager.h"
pDNM DNM_temp = NULL;
DNM_temp = DNMManager_New(); //get one DNM
DNM_temp = DNMManager_Ctor(DNM_temp, pl_p); //init DNM_temp by pl_p
The file DNM_Manager.c needs to know declaration of ATEIS_Payload_s, otherwise it cannot dereference it.
How can I do except that declare ATEIS_Payload_s again in DNM_Manager.c?
Thanks.
As Groo suggested, the implementer must offer functions to user to manipulate members. Here is a snippet from my code:
uint32_t PayloadManager_GetAddr(ATEIS_Payload_s* this)
{
return this->Addr;
}
In this code contains two structures and their naming is different. Structure member naming is same but type is different. Is there any possibility to change the structure name at run time by using macros or other functionality.
typedef struct STag_ABCRegisters
{
unsigned long aaa;
unsigned long bbb;
unsigned long ccc;
unsigned long dddd;
}RegistersABC;
typedef struct STag_CDERegisters
{
unsigned short aaa;
unsigned short bbb;
unsigned short ccc;
unsigned short dddd;
}RegistersCDE;
main()
{
int type = 1;
if(type == 1)
{
RegistersABC->ccc = 10;
}
else
{
RegistersCDE->ccc = 10;
}
/* after some process again checking the type updating structure*/
type = 2;
if(type == 1)
{
RegistersABC->aaa = 10;
}
else
{
RegistersCDE->aaa = 10;
}
}
I need the help for following process
In the above code contains complexity of if else condition.
So is there any possibilities for select the structure at run time??.
See the below Pseudo code steps for your understanding
main()
{
char type = "ABC";
Registers//type//->aaa = 10; // Type of structure name should be replaced here
}
As I stated in my comment, structures are just the way memory is organized on the machine.
If both structures were compiled by the same compiler on the same machine (architecture / OS), their memory footprint will be the same and you can simply cast their pointer to one to a pointer of the other.
This, however, is not the best way to go about "inheritance" with C.
At the moment, you can have something like this:
struct STag_ABCRegisters
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
} RegistersABC;
struct STag_CDERegisters
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
} RegistersCDE;
main()
{
(struct STag_CDERegisters*) pdata = (struct STag_CDERegisters*)&RegistersABC;
data->ccc = 10;
data->aaa = 10;
}
It works, but it isn't beautiful.
If you need two of the same, the correct way would be:
struct STag_Registers
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
};
struct STag_Registers RegistersABC, RegistersCDE;
main()
{
struct STag_Registers * data = &RegistersABC;
data->ccc = 10;
data->aaa = 10;
}
If you need struct inheritance, then the "trick" is to have the "parent" placed at the head of the struct, so that the memory footprint is aligned.
struct STag_Registers
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
};
struct STag_RegistersExtended
{
struct STag_Registers parent;
// ... more types
};
This allows a pointer to struct STag_RegistersExtended to be cast as a pointer to struct STag_Registers, so that functions that accept a pointer to struct STag_Registers can also accept a pointer to struct STag_RegistersExtended.
Good luck with C.
EDIT (answering comment)
If you're writing for an embedded system and you have reserved (fixed) memory addresses for the data, you could go with something such as:
typedef struct {
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
} register_s;
#define PTR2REG(p) ((register_s *)(p))
#define REG_A PTR2REG(0x1000))
#define REG_B PTR2REG(0x9000))
inline void perform_work(register_s * reg)
{
reg->ccc = 10;
// ...
reg->aaa = 10;
}
main()
{
perform_work(REG_A);
perform_work(REG_B);
if(REG_A->aaa == 10) // should be true
printf("work was performed");
}
You should note that struct have a memory alignment and packing order. The compiler will add padding to the struct you defined in the question, due to the long's memory alignment requirements. You can read more about struct packing here.
If your embedded system requires an exact bit / byte match (and is free from padding requirements), you should tell the complier not to add any padding. This is often done using #pragma pack
EDIT 2
I'm not sure where the type in your question is derived from... but if you have a global variable with the address for the struct, you could go with:
typedef struct {
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
} register_s;
#define PTR2REG(p) ((register_s *)(p))
#define REG_A PTR2REG(0x1000))
#define REG_B PTR2REG(0x9000))
register_s * active_register = REG_A;
inline void perform_work(void)
{
active_register->ccc = 10;
// ... active_register might change
active_register->aaa = 10;
}
main()
{
perform_work();
}
This is from a C++ perspective, you really should be more careful with those language tags if this is not what you want
Since C++ does not have reflection, it's not possible to do what you want at runtime. There are workarounds though.
For example one workaround could be to have a common base-class for the common elements (which in your simple example seems to be all). The you could have an unordered map translating strings to pointers to your structure.
Example:
struct CommonBase
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
};
struct ABC : CommonBase {};
struct DEF : CommonBase {};
int main()
{
std::unordered_map<std::string, std::unique_ptr<CommonBase>> items = {
{ "ABC", new ABC },
{ "DEF", new DEF }
};
std::cout << "Select item to modify (ABC or DEF): ";
std::string input;
std::cin >> input;
items[input]->aaa = 12;
}
For members that are not common, that are unique for each respective structure, then you need to actually check like you do now and then downcast the pointer to the correct type.
For a C solution there is none really, except to manually check like you do now.
Dynamic languages like python have buildin metadata table for reflection, so we just build one for help. Now it looks much like a script language.
_Generic need C11 std to work.
some code copied from How to save the result of typeof?
// some code copied from https://stackoverflow.com/questions/42222379/how-to-save-the-result-of-typeof
// gcc -std=c11 typeid_of_test.c
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
typedef struct STRU
{
int32_t aaa;
double bbb;
int ccc;
char dddd;
}STRU;
typedef struct Metainfo
{
int type;
char* name; //or hash
int offset;
}Metainfo;
enum {TYPE_UNKNOWN, TYPE_INT, TYPE_CHAR, TYPE_DOUBLE};
#define typeid_of(T) _Generic((T), int: TYPE_INT, long: TYPE_INT, char: TYPE_CHAR, double: TYPE_DOUBLE, default: 0)
#define META(ST_, M_) {typeid_of((__typeof__(((ST_ *)0)->M_))0), #ST_ "." #M_, offsetof(ST_, M_)}
/* { typeid, name, offset } */
Metainfo meta[]={
META(STRU, aaa),
META(STRU, bbb),
META(STRU, ccc),
META(STRU, dddd),
};
int set_by_name(char* member_name, char* value, void* p)
{
int offset=0, type=0;
for(int i=0; i<sizeof(meta)/sizeof(Metainfo); i++)
if(stricmp(member_name, meta[i].name)==0)
{
offset=meta[i].offset;
type = meta[i].type;
}
switch(type)
{
case TYPE_INT:
*(int*)((char*)p+offset) = atoi(value);
break;
case TYPE_CHAR:
*(char*)((char*)p+offset) = atoi(value);
break;
case TYPE_DOUBLE:
*(double*)((char*)p+offset) = atof(value);
break;
default:
return 0;
}
return 1;
}
int main(void)
{
for(int i=0; i<sizeof(meta)/sizeof(Metainfo); i++)
printf("type:%d, name: %s, offset: %d\n", meta[i].type, meta[i].name, meta[i].offset);
STRU b={0};
set_by_name("stru.bbb", "3.1415926", &b);
printf("stru.bbb == %f", b.bbb);
return 0;
}
The C struct:
typedef struct {
int32_t tid;
int32_t pos;
uint32_t bin:16, qual:8, l_qname:8;
uint32_t flag:16, n_cigar:16;
int32_t l_qseq;
int32_t mtid;
int32_t mpos;
int32_t isize;
} bam1_core_t;
typedef struct {
bam1_core_t core;
int l_data, m_data;
uint8_t *data;
uint64_t id;
} bam1_t;
The Julia data type I write:
type BinQualLqname
bin::UInt16
qual::UInt8
l_qname::UInt8
end
type FlagNCigar
flag::UInt16
n_cigar::UInt16
end
type Bam1_core_t
tid::Int32
pos::Int32
bin_qual_lqname::BinQualLqname
flag_ncigar::FlagNCigar
l_qseq::Int32
mtid::Int32
mpos::Int32
isize::Int32
end
type Bam1_t
core::Ptr{Bam1_core_t}
l_data::Int32
m_data::Int32
data::Ptr{Cuchar}
id::UInt64
end
When I used above Datatype Bam1_t in julia function:
function sam_read1!(samfile,bamheader,b::Ptr{Bam1_t})
record = ccall((:sam_read1,"libhts"),Cint, (Ptr{Void},Ptr{Void},Ptr{Bam1_t}),samfile,bamheader,b)
end
The data in b modified by sam_read1! is nonsense. How can I debug this? Is there any tools or tips recommended?
sam_read1
int sam_read1(tamFile fp, bam_header_t *header, bam1_t *b);
where
typedef struct {
bam1_core_t core;
int l_aux, data_len, m_data;
uint8_t *data;
} bam1_t;
Seems to be different than your Bam1_t. Would
type Bam1_t
core::Bam1_core_t
l_aux::Int32
data_len::Int32
m_data::Int32
data::Ptr{Cuchar}
end
work?
I have a struct that consists of a union, a variable and a bitfield:
typedef struct router_client {
union {
QHsm *client;
void (*handler)(QSignal sig, QParam par);
};
uint8_t level;
struct {
uint8_t presence:2;
uint8_t is_hsm:1;
uint8_t is_handler:1;
};
} router_client_t;
What is the proper way to initialize it? I used to
router_client_t = {.client=(QHsm*)&qhsm_foo, level = l, \
.presence = p, .is_hsm = s, .is_handler = a}
But when switching toolchain from Code Red MCU tools to Cross GCC I started getting
unknown field 'client' specified in initializer
unknown field 'presence' specified in initializer
...
The point of the union is that I want to be able to assign values either to client or handler and let them share the same pointer.
I tried a few things and I know I can change the struct but I just wanted to know if there is a C99 way of initializing and accessing it.
This can work. I think that the trick is name of structs and union.
typedef union {
int *client;
void (*handler)(int sig, int par);
}union_t;
typedef struct {
uint8_t presence:2;
uint8_t is_hsm:1;
uint8_t is_handler:1;
}struct_t;
typedef struct router_client {
union_t test;
uint8_t level;
struct_t test2
} router_client_t;
void main()
{
int pippo;
router_client_t pippo2= {.test.client=(int*)&pippo, .level = 10, .test2.presence = 2, .test2.is_hsm = 1, .test2.is_handler = 1};
}
Or as you wrote:
#include <stdint.h>
typedef struct router_client {
union{
int *client;
void (*handler)(int sig, int par);
}union_t;
uint8_t level;
struct {
uint8_t presence:2;
uint8_t is_hsm:1;
uint8_t is_handler:1;
}struct_t;
} router_client_t;
void main()
{
int pippo;
router_client_t pippo2= {.union_t.client=(int*)&pippo, .level = 10, .struct_t.presence = 2, .struct_t.is_hsm = 1, .struct_t.is_handler = 1};
}
I see an unnamed struct and an unnamed union.
It is highly probably that the cross gcc compiler is not handling anonymous structs and unions with what ever the default standard is.
suggest adding an appropriate parameter to the compile, something like
'-std=c11'
Say I have a C structure like:
typedef struct {
UINT8 nRow;
UINT8 nCol;
UINT16 nData; } tempStruct;
Is there a way to put all of those 3 members of the struct into a single 32-bit word, yet still be able to access them individually?
Something with the help of unions?
typedef struct {
UINT8 nRow;
UINT8 nCol;
UINT16 nData;
}
tempStruct;
typedef union {
tempStruct myStruct;
UINT32 myWord;
} stuff;
Or even better (with no "intermediate" struct):
#include <stdlib.h>
#include <stdio.h>
typedef union {
struct {
int nRow:8;
int nCol:8;
int nData:16;
};
int myWord;
} stuff;
int main(int args, char** argv){
stuff a;
a.myWord=0;
a.nCol=2;
printf("%d\n", a.myWord);
return 0;
}
What about just referring to it as a UINT32? It's not like C is type-safe.
tempStruct t;
t.nRow = 0x01;
t.nCol = 0x02;
t.nData = 0x04;
//put a reference to the struct as a pointer to a UINT32
UINT32* word = (UINT32 *) &t;
printf("%x", *word);
You can then get the value of the struct as a 32-bit word by dereferencing the pointer. The specifics of your system may matter, though...if I run this on my machine, the value of word is 0x00040201---that is, the fields are in reverse order. I don't think that's necessarily going to be the case if you're trying to serialize this to another system, so it's not portable.
If you want to actually store it as a 32-bit integer and then refer to the fields individually, why not
UINT32 word = 0x01020004;
and then somewhere else...
UINT8* row(UINT32 word) {
return (UINT8 *) &word + 3;
}
UINT8* col(UINT32 word) {
return ((UINT8 *) &word) + 2;
}
UINT16* data(UINT32 word) {
return ((UINT16 *) &word);
}
Macros will facilitate portable endianness.
Yes, you can use bit fields in C to do that. Something like:
typedef struct {
unsigned nRow : 8;
unsigned nCol : 8;
unsigned nData : 16;
} tempStruct;
If you want to control the memory layout also, you might want to take a look at #pragma pack. A non-portable option available on some compilers for this.
typedef struct {
int nRow:8;
int nCol:8;
int nData:16; } tempStruct;
nRow will take only 8 bit and nCol will take 8 bit and nDate will take 16bit.
This will work for you.
I just wrote sample program to see the size of it
#include<stdio.h>
typedef struct {
int nRow:8;
int nCol:8;
int nData:16; } tempStruct;
typedef struct {
int nRow;
int nCol;
int nData; } tempStructZ;
int main(void) {
printf("%d\n", sizeof(tempStruct));
printf("%d\n", sizeof(tempStructZ));
return 0;
}
Output:
4
16