Here is what I have, and there is still a problem - the compiler doesn't recognize the "my_reg" structure type.
../Source/functions.c:609:16: error: 'my_reg' undeclared (first use in this function)
ModBusIDReg = (my_reg)const_ModBusIDReg;
// define structure in flash with constants
struct
{
const unsigned char Reg00[32];
const unsigned char Reg01[32];
const unsigned char Reg02[32];
const unsigned short Reg03;
const unsigned short Reg04;
} const_ModBusIDReg =
{
"My String 1" ,
"My String 2" ,
"My String 3" ,
0 ,
0
};
// define structure in RAM, tag name "my_reg"
struct my_reg
{
unsigned char Reg00[32];
unsigned char Reg01[32];
unsigned char Reg02[32];
unsigned short Reg03;
unsigned short Reg04;
} ModBusIDReg;
// This statement is located in InitSys function.
// Both of the files where the structures were
// defined are included at the top of the file
// where InitSys function resides.
// Make a copy of const_ModBusIDReg from
// flash into ModBusIDReg in RAM.
ModBusIDReg = (my_reg)const_ModBusIDReg;
Any ideas on how to do the direct assignment ?
A type cast like this should resolve the compiler error:
ModBusIDReg = (my_reg)const_ModBusIDReg;
Or you could use memcpy():
memcpy(&ModBusIDReg, &const_ModBusIDReg, sizeof(my_reg));
(Sidenote at using memcpy(): In some cases, memory alignment might be an issue. But I'm no c expert. Using compiler-specific attributes like packed in the case of GCC might help, when you define the struct, depending on the platform, compiler, variable types used.)
You can also copy the members of the struct individually in a custom copy function, and initialize the unused parts if there are any. This would be clean, and very clear/explicit, and similar to a copy constructor / assignment operator used in C++ (deep copies are handled properly).
edit:
Since I can't add a comment above after your last edit, I add the comment here:
./Source/functions.c:609:16: error: 'my_reg' undeclared (first use in
this function) ModBusIDReg = (my_reg)const_ModBusIDReg;
In C you can use typedef in your struct type declartions, in order to avoid repeating the struct keyword throughout your code (explained in detail over here or there):
typedef struct { ... } foo;
foo x;
Here an example illustrating the mentioned ideas from above:
/* gcc -Wall -o copy_test copy_test.c && ./copy_test */
#include <stdio.h>
#include <string.h>
typedef struct {
int var;
} my_struct;
int my_copy_func(my_struct *dst, const my_struct *src)
{
if (!dst || !src)
return -1;
dst->var = src->var;
return 0;
}
int main()
{
const my_struct a = { .var = 42 };
my_struct b, c, d;
c = (my_struct)a;
memcpy(&b, &a, sizeof(b));
my_copy_func(&d, &a);
printf("b.var = %d\r\n", b.var);
printf("c.var = %d\r\n", c.var);
printf("d.var = %d\r\n", d.var);
return 0;
}
Related
My first question wasn't well formulated so here goes again, this time, more well asked and explained.
I want to hide the variables of a struct while being able to initialize the struct statically on the stack. Most solutions out there use the opaque pointer idiom and dynamic memory allocation which isn't always desired.
The idea for this example came from the following post:
https://www.reddit.com/r/C_Programming/comments/aimgei/opaque_types_and_static_allocation/
I know that this is probably ub but I believe it should work fine in most consumers archictures: either 32 bit or 64 bit.
Now you may tell me that sometimes size_t may be bigger than void * and that the void * alignment in the union forcing the union alignment to be that of sizeof(void *) may be wrong, but usually that's never case, maybe it can happen but I see it as the exception not the rule.
Based on the fact that most compilers add padding to align it to either a multiple of 4 or 8 depending on your architecture and that sizeof returns the correct size with padding, sizeof(Vector) and sizeof(RealVector) should be the same, and based on the fact that both Vector and RealVector have the same alignment it should be fine too.
If this is ub, how can I create a sort of scratchpad structure in C in a safe maner? In C++ we have alignas, alignof and placement new which hepls making this ordeal a lot more safer.
If that's not possible to do in C99, will it be more safer in C11 with alignas and alignof?
#include <stdint.h>
#include <stdio.h>
/* In .h */
typedef union Vector {
uint8_t data[sizeof(void *) + 2 * sizeof(size_t)];
/* this is here to the force the alignment of the union to that of sizeof(void *) */
void * alignment;
} Vector;
void vector_initialize_version_a(Vector *);
void vector_initialize_version_b(Vector *);
void vector_debug(Vector const *);
/* In .c */
typedef struct RealVector {
uint64_t * data;
size_t length;
size_t capacity;
} RealVector;
void
vector_initialize_version_a(Vector * const t) {
RealVector * const v = (RealVector *)t;
v->data = NULL;
v->length = 0;
v->capacity = 8;
}
void
vector_initialize_version_b(Vector * const t) {
*(RealVector *)t = (RealVector) {
.data = NULL,
.length = 0,
.capacity = 16,
};
}
void
vector_debug(Vector const * const t) {
RealVector * v = (RealVector *)t;
printf("Length: %zu\n", v->length);
printf("Capacity: %zu\n", v->capacity);
}
/* In main.c */
int
main() {
/*
Compiled with:
clang -std=c99 -O3 -Wall -Werror -Wextra -Wpedantic test.c -o main.exe
*/
printf("%zu == %zu\n", sizeof(Vector), sizeof(RealVector));
Vector vector;
vector_initialize_version_a(&vector);
vector_debug(&vector);
vector_initialize_version_b(&vector);
vector_debug(&vector);
return 0;
}
I'll post my answer from the previous question, which I didn't have to time to post :)
Am I safe doing this?
No, you are not. But instead of finding a way of doing it safe, just error when it's not safe:
#include <assert.h>
#include <stdalign.h>
static_assert(sizeof(Vector) == sizeof(RealVector), "");
static_assert(alignof(Vector) == alignof(RealVector), "");
With checks written in that way, you will know beforehand when there's going to be a problem, and you can then fix it handling the specific environment. And if the checks will not fire, you will know it's fine.
how can I create a sort of scratchpad structure in C in a safe maner?
The only correct way of really doing it safe would be a two step process:
first compile a test executable that would output the size and alignment of struct RealVector
then generate the header file with proper structure definition struct Vector { alignas(REAL_VECTOR_ALIGNMENT) unigned char data[REAL_VECTOR_SIZE]; };
and then continue to compiling the final executable
Compilation of test and final executables has to be done using the same compiler options, version and settings and environment.
Notes:
Instead of union use struct with alignof
uint8_t is an integer with 8-bits. Use char, or best unsigned char, to represent "byte".
sizeof(void*) is not guaranteed to be sizeof(uint64_t*)
where max alignment is either 4 or 8 - typically on x86_64 alignof(long double) is 16.
Why nor simple? It avoids the pointer punning
typedef struct RealVector {
uint64_t * data;
size_t length;
size_t capacity;
} RealVector;
typedef struct Vector {
uint8_t data[sizeof(RealVector)];
} Vector;
typedef union
{
Vector v;
RealVector rv;
} RealVector_union;
void vector_initialize_version_a(void * const t) {
RealVector_union * const v = t;
v -> rv.data = NULL;
v -> rv.length = 0;
v -> rv.capacity = 8;
}
And
One possibility is to define Vector as follows in the .h file:
/* In vector.h file */
struct RealVector {
uint64_t * data;
size_t length;
size_t capacity;
};
typedef union Vector {
char data[sizeof(struct RealVector)];
/* these are here to the force the alignment of the union */
uint64_t * alignment1_;
size_t alignment2_;
} Vector;
That also defines struct RealVector for use in the vector implementation .c file:
/* In vector.c file */
typedef struct RealVector RealVector;
This has the advantage that the binary contents of Vector actually consists of a RealVector and is correctly aligned. The disadvantage is that a sneaky user could easily manipulate the contents of a Vector via pointer type casting.
A not so legitimate alternative is to remove struct RealVector from the .h file and replace it with an anonymous struct type of the same shape:
/* In vector.h file */
typedef union Vector {
char data[sizeof(struct { uint64_t * a; size_t b; size_t c; })];
/* these are here to the force the alignment of the union */
uint64_t * alignment1_;
size_t alignment2_;
} Vector;
Then struct RealVector needs to be fully defined in the vector implementation .c file:
/* In vector.c file */
typedef struct RealVector {
uint64_t * data;
size_t length;
size_t capacity;
} RealVector;
This has the advantage that a sneaky user cannot easily manipulate the contents of a Vector without first defining another struct type of the same shape as the anonymous struct type. The disadvantage is that the anonymous struct type that forms the binary representation of Vector is not technically compatible with the RealVector type used in the vector implementation .c file because the tags and member names are different.
#include <stdio.h>
struct virus
{
char signature[25];
int size;
}v[2];
int main(void) {
static v[0] = {"Yankee",1813};
static v[1] = {"Doodle",2813};
int i;
for(i=0;i<=1;i++)
{
printf("%s %d\n",v[i].signature,v[i].size);
}
return 0;
}
I am getting the compiler error in this C code.
Error: Declaration syntax in function main()
I am guessing that there is some error in v[2], as it is associated with extern class whereas, v[0] and v[1] are associated with static class.
But, I am not sure that is this the only reason or some other ?
Edit : I have edited the code by removing the wrong syntax.
There is no error in declaration of v[2], the problem is later.
You've written
static struct v[0] = {"Yankee",1813};
which attempts to define a 0-sized array, which is not allowed by default C standard.
That said, the syntax is also horribly wrong. You don't have a proper type there, remember, struct itself is not a type, it's a keyword. struct <something> is actually a type.
Then, from the logical point of view, you probably don't want a new variable altogether. In case you want to use the array elements from the v, just use the variable name, that's all. Something like
#include <stdio.h>
struct virus
{
char signature[25];
int size;
}v[2] = { {"Yankee",1813}, {"Doodle",2813}}; //get it initialized, job done
int main(void) {
int i;
for(i=0;i<=1;i++)
{
printf("%s %d\n",v[i].signature,v[i].size);
}
return 0;
}
will do the job in much better way, IMHO.
EDIT:
In case, you're interested in assigning individual elements (not initialization), well, you cannot use a brace-enclosed initializer for that purpose, it's not meant to be RHS operand for an assignment. You need to use a compound literal for that purpose, something like
v[0] = (struct virus){"Yankee",1813};
v[1] = (struct virus){"Doodle",2813};
will also do the job.
Don't mix up struct definitions with variable declarations, that's sloppy practice.
Instead, use a typedef:
typedef struct
{
char signature[25];
int size;
} virus_t;
Then you can declare variables of this type as you please:
static virus_t v[2] =
{
{"Yankee",1813},
{"Doodle",2813}
};
Or with designated initializers:
static virus_t v[2] =
{
[0] = {"Yankee",1813},
[1] = {"Doodle",2813}
};
I am writing a program which was a struct with a need to store information on what type it's holding. The data is represented inside the the struct as a pointer to void. A short example of what I mean:
#include <stdio.h>
struct foo {
void *data;
char *type;
};
int main() {
struct foo bar = {{'a', 'b', 'c'}, "char"};
printf("%s\n", (STRING_TO_TYPE(bar.type))bar.data);
return 0;
}
I need an implementation of the STRING_TO_TYPE macro that will replace "char" with char. All of this can be evaluated at compile time for the needs of my program.
What I want to do is hold an object of any type, so using an enum or checking for string equality will not work.
Short answer: it is not possible. Not your way. Macros can produce tokens (keywords, if you like), but cannot convert strings to them.
That said, if the thing you are after is really
Being able to define a struct with a "type" of its void * somewhere in the code,
Being able to access that type as a keyword from the struct's name,
then you will most likely end up with typeof. It is a GNU extension, so it will only work in GCC, but it works.
In the example code here, you define your struct of a certain "type" with the MYSTRUCT macro and get the type using the TYPE macro. The __COUNTER__ predefined macro prevents type redefining (each struct is its own type, see gcc -E) and three macro levels for MYSTRUCT are there for proper stringification of it.
#include <stdio.h>
#define TYPE(x) typeof(x.type)
#define MYSTRUCT(name, type) MYSTRUCT_INTER(name, type, __COUNTER__)
#define MYSTRUCT_INTER(name, type, counter) MYSTRUCT_RAW(name, type, counter)
#define MYSTRUCT_RAW(xName, xType, xCounter) \
struct mystruct_## xCounter { \
void * data; \
xType type; \
} xName
int main(void) {
MYSTRUCT(foo, int);
foo.data = (void *)42;
TYPE(foo) tmp = foo.data; /* <-- Here, tmp is an int */
printf("%d\n", tmp);
MYSTRUCT(bar, int*);
bar.data = &tmp;
TYPE(bar) tmp2 = bar.data; /* <-- Here, tmp2 is an int* */
printf("%p\n", tmp2);
MYSTRUCT(baz, char*);
baz.data = "Hello world";
printf("%s\n", (TYPE(baz))baz.data);
/* ^Expands to (char *) baz.data */
}
Note that I still need to know the struct's "type" to determine printf()'s format code, but solving this was not asked.
Don't forget to compile with -std=gnu** (you need it for typeof)
I want to be able to do something like this:
typedef struct
{
char* c_str;
} string;
string s = "hello";
Is it possible to do that in any way?
I know that it is possible to do this:
typedef struct
{
char* c_str;
} string;
string s = { "hello" };
But I do not like the curly brackets when it is only one member variable.
You could use a typedef instead of a struct:
typedef char* string;
string s = "hello";
But then const string would make the pointer const, and not the pointed-to data. So const string s is equivalent to char* const s. A solution may be to define an additional type for const strings:
typedef char* string;
typedef const char* const_string;
For the original struct, the same is true. (C++ has the same "problem", which is why it has iterator and const_iterator in its container types.)
An advantage of a typedef for a pointer type is that you can type
string s1, s2, s3;
instead of
char *s1, *s2, *s3;
In C, it is not possible, but you can do it in C++ if you add constructor that takes one appropriate parameter. Compiler will do the rest. You can mark the constructor as explicit if you want to avoid this implicit conversion behaviour.
In C++:
struct string {
char * m_c_str;
/* explicit */ string(char* c_str) : m_c_str(c_str) { }
};
int main(int argc, char * argv[]) {
string s = "hello";
return 0;
}
Is it possible to do that in any way?
No. It is not possible to do it with struct or union. Para 16 of section 6.7.9 states that
[...] the initializer for an object that has aggregate or union type shall be a braceenclosed list of initializers for the elements or named members.
There is another way to do the same with different data type as explained in this answer.
Not sure if this is actually canonical and fits the C Standards as Microsoft Visual Studio has the reputation of being a bit loose in interpreting the standard, however here is an approach that compiles and works when viewed in the debugger of Visual Studio 2005.
Though if you do not like curly brace initializers you probably would not care for a macro either.
typedef struct {
char *c_str;
} String;
// following macro assigns the string to the struct member and uses the
// comma operator to make the statement return the original struct variable.
#define xString(x, y) ((x).c_str = (y), (x))
void jjj (void)
{
String b = xString(b,"hello");
}
I was able to define multiple variables at a time so multiple variable definitions on the same line compiles as in:
String b = xString(b,"hello"), c = xString(c,"Jello");
It might be that you would want to have a macro that would do the entire statement in a kind of functional language looking construct though there could only be one per statement so multiple on the same line would require semicolons to separate into individual definition statements.
#define xString(x,y) String x = (x.c_str = (y), x)
and it would be used as
void jjj (void)
{
xString(myStruct, "hello");
int j = 2;
// .. do stuff
}
or you could just use
#define xString(x,y) String x = {y}
Initializer list really does seem to be the best approach if you want a struct for some reason to allow compile time argument checking on a specific type of char *.
Where it gets kind of awesome is when you do something like the following to initialize multiple struct members at the time the struct variable is defined.
typedef struct {
int len;
char *c_str;
} String2;
#define yString(x,y) x = (x.c_str = (y), x.len = strlen(y), x)
void jjj (void)
{
String2 b2 = yString(b2,"Hello");
int j = 2;
// .. do stuff
}
Being curious I tried another variation that looks like the following. This does move away from the specific question and more into what are possibilities of following this approach down the rabbit hole. Using the same struct with a different macro that allows you to specify a struct member to initialize along with the value.
typedef struct {
int len;
char *c_str;
} String2;
#define zString(x,y,a,b) x=(x.c_str=(y),x.a=(b),x)
void jjj (void)
{
String2 b3 = zString(b3,"Hello",len,72);
// ... do stuff
}
I have defined the structure in a separate header file and I have included that header file in my main file.
The header file consists of a structure like this:
typedef struct
{
char name[32];
unsigned int a;
unsigned int b;
NUMBER_ONE variable1;
NUMBER_TWO variable2;
}NUMBER_THREE,*PNUMBER_THREE;
typedef struct
{
unsigned int variable3;
char variable4[8];
}NUMBER_ONE,*PNUMBER_ONE;
typedef struct
{
unsigned int variable5;
char variable6[8];
}NUMBER_TWO,*PNUMBER_TWO;
Now in my main file I have to allocate memory for this structure and I need to fill this structure with some values, so anybody please tell me how to do this. I need to send this through socket client to the socket server.
If you have written it in that order you present it, then the code should not even compile since the first typedef has no clue on what NUMBER_ONE or NUMBER_TWO types are.
To allocate it should just be to define a variable of given type.
int main()
{
NUMBER_TWO number_two_var;
number_two_var.variable5 = 10;
}
I would also recommend using a postfix for each typdef, for example NUMBER_TWO_T.
Edit: Postfix being _T
In C a struct is initialized by an initializer
NUMBER_TWO a2 = { .variable5 = 7, .variable6 = { 'a', }, };
the form I am giving here are so-called designated initializers that came starting with C99. Oldish C had only the equivalent
NUMBER_TWO a2 = { 7, { 'a' } };
where you have to specify the values in declaration order.
For both forms, fields that are omitted from the initializer are initialized with 0.