union of value and function pointer - c

I am struggling with using unions. Why am I unable to pass the function pointer to where the union would be? Any help would be greatly appreciated.
Edit: removed a typedef
#include <stdio.h>
union U {
int(*fnPtr)(int);
int i;
};
enum E {
OPTION_0 = 0,
OPTION_1 = 1
};
int multiply_by_two (int x) {
return 2 * x;
}
int f (int x, enum E e, union U u) {
switch (e) {
case OPTION_0:
/* Return the sum */
return x + u.i;
case OPTION_1:
/* Return 2 * x */
return u.fnPtr (x);
}
}
int main (void) {
int a;
scanf ("%d", &a);
int b = f (a, OPTION_1, &multiply_by_two);
printf ("%d\n", b);
return 0;
}

First, this definition is not valid:
union U {
typedef int(*fnPtr)(int);
int i;
};
You can't have a typedef inside of a struct or union. Removing the typedef will give you a proper definition:
union U {
int(*fnPtr)(int);
int i;
};
The second problem is here:
int b = f (a, OPTION_1, &multiply_by_two);
The function f expects a union U, but you're passing it a int (*)(int). Those types are not compatible. Just because the union has a member of that type doesn't mean you can use that type wherever you would use the union. You need to create a union, set the proper field, then pass that to the function.
union U u;
u.fnPtr = multiply_by_two;
int b = f (a, OPTION_1, u);

In main function, try this:
int main()
{
...
union U myUnion;
myUnion.fnPtr = &multiply_by_two;
int b = f (a, OPTION_1, myUnion);
...
}
And also, the union definition is not correct, you need to remove typedef.

Just to add to other answers: this is usually called a variant data type, and it makes sense to keep the type enum in a struct, along with the union, since you will be passing it around all the time anyway.
So I would recommend placing both in a struct:
enum var_type
{
VAR_INT = 0,
VAR_FUNC = 1
};
struct variant
{
// contains the type of the stored value
enum var_type type;
// contains the actual value
union {
int(*fnPtr)(int);
int i;
};
};
And then you can have separate functions for creating each subtype, for simpler instantiation:
// wrap the int value in the variant struct
struct variant variant_create_int(int i)
{
return (struct variant){ .type = VAR_INT, .i = i };
}
// wrap the functino pointer in the variant struct
struct variant variant_create_func(int(*fnPtr)(int))
{
return (struct variant){ .type = VAR_FUNC, .fnPtr = fnPtr };
}
Meaning your main would do something like:
// create variant of type 'VAR_FUNC'
struct variant var = variant_create_func(&multiply_by_two);
and just pass the var struct forward.

Related

C flexible array define with another type instead of malloc

the general usage of flexible array is to use malloc to define the flexible array. I'm trying to explore defining the flexible array with another struct. An example
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
typedef struct {
test_base_t base;
float data[3];
} test_t;
As I understand, flexible array needs to be defined at the end of a struct. And clangd will give the following warning. -Wgnu-variable-sized-type-not-at-end
I just wanted to ask if anybody has done this before and is it safe? Or is there a better way to define flexible array size without alloc?
You can then wrap the usage of the object in a macro to static assert ext.base.data == ext.data before casting and passing to a general API consumes test_base_t. This way you can have the memory required in compile instead of allocing.
Edit
There seem to be a confusion on how I wanted to consume it, here is an example to demonstrate
#define SUM_BASE(test) \
sum_base(&test->base); \
_Static_assert(test->data == test->base.data);
float sum_base(test_base_t *base)
{
float sum = 0;
for (size_t i = 0; i < base->data_size; i++)
{
sum += base->data[i];
}
return sum;
}
test_t test = { .base = { .data_size = 3, }, .data = { 1, 2, 3, }, };
SUM_BASE((&test));
You cannot create actual instances of test_base_t with an initialized array, but you can create compound literals with an initialized array of a specified length and cast their address as test_base_t pointers. The layout and alignment of both structures should be compatible, given that they have exactly the same types, save for the flexible array length.
Here is an example:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
#define TEST_ARRAY(n) (test_base_t*)&(struct { uint64_t header; \
size_t data_size; \
float data[n]; })
float sum_base(const test_base_t *p) {
float sum = 0.F;
for (size_t i = 0; i < p->data_size; i++) {
sum += p->data[i];
}
return sum;
}
void print_test(const test_base_t *p) {
printf("%"PRIu64" %zu { ", p->header, p->data_size);
if (p->data_size) {
printf("%g", p->data[0]);
for (size_t i = 1; i < p->data_size; i++) {
printf(" %g", p->data[i]);
}
}
printf(" } sum=%g\n", sum_base(p));
}
int main() {
test_base_t *p1 = TEST_ARRAY(1){.data_size = 1, .data = {1}};
test_base_t *p2 = TEST_ARRAY(2){.data_size = 2, .data = {1, 2}};
print_test(p1);
print_test(p2);
print_test(TEST_ARRAY(3){.data_size = 3, .data = {1, 2, 3}});
print_test(TEST_ARRAY(4){.data_size = 4, .data = {1, 3, 5, 7}});
return 0;
}
Here is another approach, perhaps closer to your expectations, using a union with a base member with the flexible type and a parametric instance type with the appropriate array size:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint64_t header;
size_t data_size;
float data[];
} test_base_t;
/* parametric type template using C macros */
/* structures with a flexible array can be members of union types */
#define test_base_t(...) \
union { \
test_base_t base; \
struct { \
uint64_t header; \
size_t data_size; \
float data[__VA_ARGS__]; \
}; \
}
float sum_base(const test_base_t *p) {
float sum = 0.F;
for (size_t i = 0; i < p->data_size; i++) {
sum += p->data[i];
}
return sum;
}
void print_test(const test_base_t *p) {
printf("%"PRIu64" %zu { ", p->header, p->data_size);
if (p->data_size) {
printf("%g", p->data[0]);
for (size_t i = 1; i < p->data_size; i++) {
printf(" %g", p->data[i]);
}
}
printf(" } sum=%g\n", sum_base(p));
}
int main() {
test_base_t(1) t1 = { .data_size = 1, .data = {1} };
test_base_t(2) t2 = { .data_size = 2, .data = {1, 2} };
/* the print_test function can be called without casts */
print_test(&t1.base);
print_test(&t2.base);
print_test(&((test_base_t(3)){.data_size = 3, .data = {1, 2, 3}}).base);
print_test(&((test_base_t(4)){.data_size = 4, .data = {1, 3, 5, 7}}).base);
return 0;
}
C 2018 6.7.2.1 3 says of a structure containing a flexible array member:
… such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
Thus, the test_t type in the question violates this “shall” requirement, and C 2018 4 2 says that makes the behavior not defined by the C standard. A compiler could reject this code. If the compiler accepts it, the behavior of the program is not defined by the C standard.
As an example of what could go wrong (in that the C standard allows it), consider this code:
test_t test = { .base = { .data_size = 3, }, .data = { 1, 2, 3, }, };
printf("%g\n", test.base.data[0]);
Since test.base.data[0] was never assigned a value through that expression, and the standard does not define test.data to alias test.base.data, the compiler may assume the value of test.base.data[0] is uninitialized and hence unspecified, and this printf may use any value of the float type, even if test.base.data[0] and test.data[0] nominally refer to the same memory.
And in this code:
test_t test = { .base = { .data_size = 3, } };
for (int i = 0; i < 4; ++i)
test.base.data[i] = i+1;
test_t copy = test;
The compiler may assume that, since test.data was never initialized, it does not need to be copied to copy when initializing it from test.

C incomplete Type in structs

He folks,
i got a problem and a question.
Hopefully u can help and explain me.
first of all i have 2 stucts:
typedef struct {
double x;
double y;
} A;
typedef struct {
unsigned int count;
A(*stack)[];
}B;
this struct B i declare in main() and passing a Pointer of B to a function this will initializ
main(){
B x;
function rr(&x);
}
void rr(B* test) {
test->stack= malloc((4) * sizeof(A)); //4Elements
for (unsigned int i = 0; i < 4; i++) {
(test->stack+ i)->x= 89;
}
}
on this line
(test->stack+ i)->x= 89;
compiler says incomplete Type
i know why it is incomplete cause in struct B their is no dimension.
but array should initialize in function rr
Maybe u understand what i mean and how to solve my problem.
function rr i am not allowed to change.
Greetings
EDIT 1
Thank you for all answers
mabey i schould clearify my problem
typedef struct {
unsigned int count;
A(*stack)[]; // here i want a pointer to an array of A's
}B;
//over main it is declared
void rr(B*);
main(){
B x;
function rr(&x);
}
// this func is not allowed to change
void rr(B* test) {
test->stack= malloc((4) * sizeof(A)); //4Elements
for (unsigned int i = 0; i < 4; i++) {
(test->stack+ i)->x= 89; // error cause incomplete type but i
//have to use this line
}
}
Hope now it is easier to i understand what i want
This declaration:
A(*stack)[];
Says that stack is a pointer to an array of A of unknown size. That is an incomplete type which means it can't be used directly.
It seems like what you actually want is not a pointer to an array, but a pointer to the first member of a dynamic array of A. So declare the member as a pointer:
A *stack;
In the expression:
(test->stack+ i)->x= 89;
before accessing an array via a pointer to an array you must dereference it.
Try:
(*test->stack)[i].x= 89;
You do not know how to use flexible array members.
Simply:
typedef struct {
double x;
double y;
} A;
typedef struct {
size_t count;
A stack[];
}B;
B *createStack(size_t size)
{
B *s = malloc(sizeof(*s) + size * sizeof( s -> stack[0]));
return s;
}
void rr(B* test) {
for (unsigned int i = 0; i < 4; i++) {
(test->stack+ i)->x= 89;
}
}
int main(void)
{
B *stack = createStack(4);
rr(stack);
free(stack);
}
You need only one allocation to mallloc/realloc or free the structure. The array will decay into pointer for your assignment in rr function.

Array of functions with built in arguments in C

Say I have these two functions and a definition of an array of these two functions:
int flag;
int add(int a, int b){
return a+b;
}
int multiply(int a, int b){
return a*b;
}
typedef int(*f)(int, int);
f func_array[2] = {&add, &multiply};
Now, there is a specific place in my code that I want to call these two functions depending on my flag state with the same arguments each time.
For example:
int var;
if(flag == 0)
{
var = func_array[flag](1,1);
}
else{
var = func_array[flag](2,2);
}
Is there a way to define it inside the array itself? Somwhow defining the array like this and just call the function:
f func_array[2] = {&add(1,1), &multiply(2,2)};
int var = func_array[flag]();
Is this a valid way? Is there any more elegant way to do it?
You can define a set of arrays for each parameter:
#define ARR_SIZE 2
typedef int(*f)(int, int);
f func_array[ARR_SIZE] = {&add, &multiply};
int param1_array[ARR_SIZE] = { 1, 2};
int param2_array[ARR_SIZE] = { 1, 2};
The call would become
if(flag < ARR_SIZE)
{
int var = func_array[flag](param1_array[flag], param2_array[flag]);
}
I just added a check on the array size.
With a macro
#define flag_call(flag) \
func_array[flag](param1_array[flag], param2_array[flag])
you could simplify it even more
if(flag < ARR_SIZE)
{
flag_call(flag);
}
Not sure what the point is but you can do this:
int add11(void){ return add(1,1); }
int multiply22(void){ return multiply(2,2); }
/*skipped the new typedef*/
int (*func_array2[2])(void) = {&add11,&multiply22};
https://godbolt.org/z/ejMn4n
The wrappers could even be inlinable if you make the array static or auto.
You can use a struct to bundle them together:
typedef int(*f)(int, int);
struct func_and_args {
f func;
int a;
int b;
}
...
struct func_and_args arr[] = {{&add,1,1},{&multiply,2,2}};
int var = arr[flag].func(arr[flag].a,arr[flag].b);

right arrow equals right arrow

I saw something in someones code that I don't understand. What does it say in the return statement?
static cell_ptr UD_self(cell_ptr c) { return c->U = c->D = c; }
here is defined:
struct cell_s;
typedef struct cell_s *cell_ptr;
struct cell_s {
cell_ptr U, D, L, R;
int n;
union {
cell_ptr c;
int s;
};
};
It's just a shorthand way of writing this:
{
c->D = c;
c->U = c->D;
return c->U;
}
The statement return c->U = c->D = c; works because the assignment operator = returns the value it has just assigned. This value is then used in the next assignment. It associates from right to left, so it means return (c->U = (c->D = c));

Adding (or doing any other math) every member of two same structs with less code

So, basically, I want to addify every member of first struct, with every member of second struct, and the structs are of same type. Like this:
struct Foo
{
int bar1;
int bar2;
int bar3;
int bar4;
int bar5;
}
Foo AddFoos(Foo foo1, Foo foo2)
{
Foo foo3;
foo3.bar1 = foo1.bar1 + foo2.bar1;
foo3.bar2 = foo1.bar2 + foo2.bar2;
foo3.bar3 = foo1.bar3 + foo2.bar3;
foo3.bar4 = foo1.bar4 + foo2.bar4;
foo3.bar5 = foo1.bar5 + foo2.bar5;
return foo3;
}
However, when structs keep getting bigger, this way is weird. Is there any way to do it with less lines of code? And preferably without advanced pointer magic?
Use an array instead and a for loop to add the numbers:
struct Foo
{
int bars[100];
};
for (i=0;i<100;i++)
{
foo3.bars[i]=foo1.bars[i]+foo2.bars[i];
}
You can malloc if the array size is unknown at compile time and change the struct to this and then malloc for all three Foo variables.
struct Foo
{
int *bars;
};
You want the comfort of named fields (bar1 .. barN) and something like an array you can loop over to automate the operations. First we define the struct (a dense representation of the fields in memory):
struct VectorFields {
int a;
int b;
int c;
};
Then we need to get to know the number of the fields used in that struct:
#define VECTOR_FIELDS_LEN (sizeof(struct VectorFields) / sizeof(int))
(In C++ you could use some template magic foo, here we just use the preprocessor as a simpler variant). Next, we combine the struct VectorFields with an array of int so both match in size, also known as union:
union Vector {
struct VectorFields fields;
int raw[VECTOR_FIELD_LEN];
};
(Note: VECTOR_FIELD_LEN must be a known constant value to the compiler, hence the preprocessor thingy before.) You are now able to access the data either by it's name (.fields.a) or by an index (.raw[0]). So, let's write the function which adds the Vector together:
void vector_add(union Vector* result, union Vector* a, union Vector* b) {
int i;
for (i = 0; i < TUPLE_LEN; i++) {
result->raw[i] = a->raw[i] + b->raw[i];
}
}
You might use it like this then:
#include <stdio.h>
int main() {
union Vector a = { .fields = { 1, 2, 3 } };
union Vector b = { .fields = { 4, 5, 6 } };
union Vector sum;
vector_add(&sum, &a, &b);
printf("%d %d %d\n", sum.fields.a, sum.fields.b, sum.fields.c);
return 0;
}
Depending on what you call "advanced pointer magic", you can use the following moderately magical code:
Foo AddFoos(Foo foo1, Foo foo2)
{
Foo foo3;
int *pointer1 = &foo1.bar1; // first field here
int *pointer2 = &foo2.bar1; // first field here
int *pointer3 = &foo3.bar1; // first field here
while (pointer3 <= &foo3.bar5) // last field here
{
*pointer3++ = *pointer1++ + *pointer2++;
}
return foo3;
}
When you change the definition of Foo, just update the names of the first and last field.
This will only work when all fields are of the same type.
If you have only ints you can use an array
struct Foo {
int bar[5];
};
Foo AddFoos(Foo f1, Foo f2)
{
Foo f3;
int i;
for (i = 0; i < 5; ++i)
f3.bar[i] = f1.bar[i] + f2.bar[i];
return f3;
}

Resources