Tail-calls corrupted when compiled with __attribute__((musttail)) - c

I was working a Lisp interpreter with a 'threaded' design, where it compiles to a VM where each instruction is a C function that calls the next instruction — if the compiler does tail call elimination, then it should only need a jmp between instructions.
It's a stack-oriented VM, with an Imm instructions that pushes an immediate to the stack.
When I manually call the first Imm instruction, it runs fine. However, once the Imm instruction jumps to the next Imm instruction, it seems the call stack becomes corrupted as none of the parameter values are valid anymore. However, this only occurs when I use clang with __attribute__((musttail)). In fact, gcc -O3 and even clang -O3 compile it to a jmp just fine (but clang without musttail compiles to a call). Anyone know what could be going on here?
A stripped-down version of the code that exhibits this behavior follows:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef enum { TypeInt = 0 } Tag;
typedef struct {
int n; /* item count */
int64_t *val; /* pointer */
} List;
typedef struct Block {
struct Ins *ins;
int n;
struct Fn *fn;
struct Scope *locals;
struct Scope *mod;
} Block;
typedef struct Scope {
int n;
const char **names;
int64_t *vals;
Block first;
} Scope;
typedef struct Ins {
char (*op)(int, Block);
int64_t imm;
} Ins;
typedef struct Fn {
Scope locals;
Scope *mod;
} Fn;
int64_t *stack;
uint32_t sc; /* stack counter */
uint32_t fc; /* frame counter */
uint32_t cap = 128 * sizeof(int64_t);
#define F_INS(x) char x(int ic, Block b)
#define MUSTTAIL __attribute__((musttail))
#define INSRET MUSTTAIL return b.ins[ic + 1].op(ic + 1, b);
#define N_BUILTINS 1
const char *builtins[N_BUILTINS] = { "+" };
void vm_init(void) { stack = malloc(cap); }
F_INS(Done) { return 0; }
void stack_push(int64_t v)
{
if (++sc >= cap) stack = realloc(stack, cap *= 2);
stack[sc - 1] = v;
}
F_INS(Imm)
{
printf("IC: %u\n", ic);
stack_push(b.ins[ic].imm);
INSRET;
}
F_INS(Add)
{
int64_t y = stack[--sc];
int64_t x = stack[--sc];
stack_push(x + y);
INSRET;
}
int main(int argc, char **argv)
{
Block b = {0};
vm_init();
b.ins = realloc(b.ins, ++b.n * sizeof(Ins));
b.ins[b.n - 1].op = &Imm;
b.ins[b.n - 1].imm = 3;
b.ins = realloc(b.ins, ++b.n * sizeof(Ins));
b.ins[b.n - 1].op = &Imm;
b.ins[b.n - 1].imm = 4;
b.ins = realloc(b.ins, ++b.n * sizeof(Ins));
b.ins[b.n - 1].op = &Add;
b.ins = realloc(b.ins, ++b.n * sizeof(Ins));
b.ins[b.n - 1].op = &Done;
(*b.ins[0].op)(0, b);
}
When I remove the structs for Fn and Scope, or when I turn optimizations on, it doesn't crash anymore. Bizarrely, it works fine with fsanitize=memory.
The full code is at https://git.sr.ht/~euclaise/trent/tree/
clang version 14.0.6
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

Related

gcc.exe warning cast from pointer to integer of different size [-Wpointer-to-int-cast]

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef void SeqList;
typedef void SeqListNode;
typedef unsigned int TSeqListNode;
typedef unsigned int TSeqListNode;
typedef struct _tag_SeqList
{
int capacity;
int length;
TSeqListNode *node;
}TSeqList;
SeqList * SeqList_Create(int capacity)
{
TSeqList *ret = NULL;
if(capacity>=0)
{
ret = (TSeqList *)malloc(sizeof(TSeqList) + sizeof(TSeqListNode)*capacity);
}
if(ret == NULL)
{
printf("malloc fail.\n");
exit(-1);
}
ret->capacity = capacity;
ret->length = 0;
ret->node = (TSeqListNode*)(ret+1);
return ret;
}
int SeqList_Insert(SeqList *list, SeqListNode *node, int pos)
{
TSeqList *sList = (TSeqList*)list;
int ret = (sList != NULL);
int i = 0;
ret = ret && (sList->length+1 <= sList->capacity);
ret = ret && (0 <= pos);
if(ret)
{
if(pos >= sList->length)
{
pos = sList->length;
}
for(i=sList->length; i > pos; i--)
{
sList->node[i] = sList->node[i-1];
}
sList->node[i] = (TSeqListNode)node;
sList->length++;
}
return ret;
}
int main()
{
system("pause");
return 0;
}
D:\mingw64\bin\gcc.exe -g D:\Cpp\DSA\test001.c -o D:\Cpp\test001.exe
D:\Cpp\test001.c: In function 'SeqList_Insert':
D:\Cpp\test001.c:56:26: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
sList->node[i] = (TSeqListNode)node;
^
What you are trying to do is already part of the ISO/IEC 9899:1999 C standard. It's called flexible array member. So no need for inventing your own code - just use what is already available.
Also notice that capacity and length are variables that can't be negative. So you should use an unsigned type. The common used type would be size_t.
So your code should be:
typedef struct _tag_SeqList
{
size_t capacity;
size_t length;
TSeqListNode node[]; // Flexible array member
} TSeqList;
Now you can simply do:
ret = malloc(sizeof(TSeqList) + sizeof(TSeqListNode)*capacity);
\--------------/ \----------------------------/
Memory for the Memory for the 'node' array
struct, i.e for with 'capacity' elements
capacity and
length
to allocate (no need for checking the value of capacity as it can't be negative).
And just use node as a normal array.
All the need for casts are gone.
Earlier versions of the C standard (C90) probably do necessitate casting. I think a placeholder data (int *)(array + 1) is entirely appropriate in some situations, assuming alignment is respected. Note that you might also make this design decision to comply with MISRA C 2012 Rule 18.7. I have eliminated the obfuscating typedefs and renamed parts of it to reflect what it actually does more clearly. A cast to void * is basically turning off type-checking, (through a typedef or not,) and should be avoided where possible.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct IntArray {
size_t capacity;
size_t length;
int *node;
};
/** #throws[malloc] */
static struct IntArray *IntArray_Create(const size_t capacity)
{
struct IntArray *ret = NULL;
ret = malloc(sizeof *ret + sizeof *ret->node * capacity);
if(ret == NULL) return 0; /* Let the caller decide what to do. */
ret->capacity = capacity;
ret->length = 0;
ret->node = (int *)(ret+1);
return ret;
}
/** Returns false if the `array` is full or null. Clips `pos` to `array`. */
static int IntArray_Insert(struct IntArray *array, const int node, size_t pos)
{
if(!array || array->length >= array->capacity) return 0;
if(pos >= array->length) pos = array->length;
/* Replaced looping over the array for performance. */
memmove(array->node + pos + 1, array->node + pos, array->length - pos);
array->length++;
array->node[pos] = node;
return 1;
}
#include <assert.h>
int main(void)
{
struct IntArray *a;
if(!(a = IntArray_Create(3))) { perror("fail"); return EXIT_FAILURE; };
assert(IntArray_Insert(a, 1, 42));
assert(IntArray_Insert(a, 3, 1));
assert(IntArray_Insert(a, 2, 1));
assert(!IntArray_Insert(a, 2, 1));
free(a);
return 0;
}
If you are targeting C99 or later, the flexible array member may be useful for this exact reason. If this is part of a macro, the only typedef you really need is typedef int ArrayType;.

invalid use of incomplete typedef in C

I'm implementing a data structure in C and I get this error in my test file. Without adding code because then that would be a huge post with a ton of code to go through, but here's what my code looks like:
header.h file:
typedef struct array Arr;
functions.c file:
#include "header.h"
struct array{
int number;
int size;
char *names;
}
main.c file:
#include "header.h"
bool function(const Arr *const variable)
{
for (int i = 0; i < variable->size; i++)
{
variable->number[i] = i;
}
}
and so I get the error mentioned in the title referring to Arr*->number and Arr->*size. What I suspect to be the issue is that Arr is only typedefed but not defined. If that's the case, how can I resolve it?
Here's the main code:
main.c
#include <stdio.h>
#include "header.h"
int main(){
set *setA = set_empty();
set_insert(69,setA );
set_insert(15, setA);
set *setB = set_empty();
set_insert(12,setB );
set_insert(15, setB);
set *setDiff = set_difference(setA, setB);
printf("\n");
print_set(setDiff);
bool diff = verify_difference(setDiff, setA, setB);
}
bool verify_difference(const set *const setDiff, const set *const setA, const struct set *const setB)
{
bool answer = true;
for (int x = 0; x < setDiff->size; x++)
{
if (set_member_of(setDiff->array[x], setA) && set_member_of(setDiff->array[x], setB))
{
answer = false;
break;
}
}
return answer;
}
header.h
#ifndef HEADER_H
#define HEADER_H
#include <stdbool.h>
typedef struct set set;
set *set_empty();
void set_insert(const int value, set *s);
bool set_member_of(const int value, const set *const s);
functions.c
#include <stdio.h>
#include "header.h"
struct set {
int capacity;
int size;
char *array;
};
set *set_empty()
{
struct set *ptr = malloc(sizeof(struct set));
ptr->size = 0;
ptr->array = malloc(sizeof(char));
ptr->capacity = 1;
return ptr;
}
void set_insert(const int value, set *s)
{
if (!set_member_of(value, s)) {
int bit_in_array = value; // To make the code easier to read
// Increase the capacity if necessary
if (bit_in_array >= s->capacity) {
int no_of_bytes = bit_in_array / 8 + 1;
s->array = realloc(s->array, no_of_bytes);
for (int i = s->capacity / 8 ; i < no_of_bytes ; i++) {
s->array[i] = 0;
}
s->capacity = no_of_bytes * 8;
}
// Set the bit
int byte_no = bit_in_array / 8;
int bit = 7 - bit_in_array % 8;
s->array[byte_no] = s->array[byte_no] | 1 << bit;
s->size++;
}
}
set *set_difference(const set *const s1, const set *const s2)
{
struct set *s = set_empty();
for (int i = 0; i < s1->size; i++)
{
if (!set_member_of(s1->array[i], s2))
{
set_insert(s1->array[i], s);
}
}
for (int i = 0; i < s2->size; i++)
{
if (!set_member_of(s2->array[i], s1))
{
set_insert(s2->array[i], s);
}
}
return s;
}
bool set_member_of(const int value, const set *const s)
{
int bit_in_array = value;
if (bit_in_array >= s->capacity) {
return false;
}
int byte_no = bit_in_array / 8;
int bit = 7 - bit_in_array % 8;
char the_byte = s->array[byte_no];
return the_byte & 1 << bit;
}
The definition of the structure shall be available in main. Otherwise the compiler does not know whether there is the data member number in the structure referred in this statement
Arr->number[i] = i;
Moreover in any case this statement is incorrect because Arr is a type specifier and according to the structure definition the data member number is not an array
It seems you mean
variable[i].number = i;
But as the function parameter
bool function(const Arr *const variable)
is declared as a pointer to a constant object then you may not change pointed to data members of the structure.
So either move the definition of the function function from main.c in functions.c or place the structure definition in the header file.
And there is a typo
Typedef struct array Arr;
^^T
you need to use lower case letter
typedef struct array Arr;
I can only hazard a guess. Your code snippet could be wrong.
Move the structure definition to header.h & check.
//header.h file:
typedef struct array Arr;
struct array{
int number;
int size;
char *names;
};

C iterate array by known sizeof

I'm trying to make a small library for particle management that allows to "expand" struct with user's data (texture, animation frames, etc). The library would know only the size of the expanded struct.
How do I iterate through the array of unknown struct types but known size of a struct?
typedef struct{
int type;
}Base;
typedef struct{
Base base;
int value;
}inherited;
int main(){
size_t size = sizeof(inherited);
int count = 10;
void *b = malloc(size * count);
for (int i = 0; i < count; i++){
// iterate based on known size & send to callback
callback( &( (size)b )[i] );
}
free(b);
return 0;
}
I assume the code that does the malloc and calls callback doesn't know anything about the type of the object, only its size.
#include <stdlib.h>
void *alloc_and_init(size_t nmemb, size_t size, void (*callback)(void *))
{
void *b = calloc(nmemb, size);
if (b)
{
char *p = b;
for (size_t i = 0; i < nmemb; i++)
{
callback(p);
p += size;
}
}
return b;
}
typedef struct{
int type;
}Base;
typedef struct{
Base base;
int value;
}inherited;
void init_inherited(void *p)
{
inherited *obj = p;
/* do initialization of obj->* here */
}
int main(void)
{
int objcount = 10;
inherited *objarr;
objarr = alloc_and_init(objcount, sizeof(*objarr),
init_inherited);
/* ... */
free(objarr);
}
for( inherited *p = b, *e = p + count; p < e; p++ ){
callback(p);
}
char *b = malloc(size * count);
for (int i = 0; i < count; i++){
// iterate based on known size & send to callback
callback( b + i * size );
}
Polymorphism in C is always rather clunky. Basically you have to construct a "vtable" manually. The naive, simplified version below lets each object have its own function pointer. You'll end up with something rather contrived like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct base_t base_t;
typedef void callback_t (const base_t* arg);
struct base_t
{
int type;
callback_t* callback;
};
typedef struct
{
base_t base;
int value;
} inherited_t;
void callback_base (const base_t* arg)
{
puts(__func__);
}
void callback_inherited (const base_t* arg)
{
const inherited_t* iarg = (const inherited_t*)arg;
printf("%s value: %d\n", __func__, iarg->value);
}
int main (void)
{
// allocate memory
base_t* array [3] =
{
[0] = malloc(sizeof(inherited_t)),
[1] = malloc(sizeof(base_t)),
[2] = malloc(sizeof(inherited_t)),
};
// initialize objects
*(inherited_t*)array[0] = (inherited_t){ .base.callback=callback_inherited, .value = 123 };
*(array[1]) = (base_t){ .callback=callback_base };
*(inherited_t*)array[2] = (inherited_t){ .base.callback=callback_inherited, .value = 456 };
for (int i = 0; i < 3; i++)
{
array[i]->callback(array[i]); // now we get polymorphism here
}
}
A more professional version involves writing a translation unit (.h + .c) per "class" and then combine allocation with initialization in the "constructor". It would be implemented with opaque type, see How to do private encapsulation in C? Inside the constructor, set the vtable corresponding to the type of object allocated.
I'd also boldly claim that any OO solution using void* arguments has some design flaw. The interface should be using the base class pointer. Void pointers are dangerous.

Reducing code duplication in C program with nearly identical statements in if/else?

I am trying to reduce code duplication in my C program, where all the statements in each branch of an if/else block are identical, except for a function name and its arguments. The idea is that the user specifies either x, y, or z, and the program measures how long it takes to run either func_x, func_y, or func_z 1000 times.
More specifically, here is the high level design of the C code:
// struct definitions
struct dat_x {...};
struct dat_y {...};
struct dat_z {...};
// reading structs from a text file
struct dat_x read_dat_x_from_file(char *path);
struct dat_y read_dat_y_from_file(char *path);
struct dat_z read_dat_z_from_file(char *path);
// functions
int func_x(struct dat_x);
int func_y(struct dat_y);
int func_z(struct dat_z);
// runner computing runtime of func_x, func_y, or func_z
int main(int argc, char** argv) {
char *func_name = argv[1];
char *path = argv[2];
int a;
clock_t t;
if (strcmp(func_name, "x") == 0) {
struct dat_x args = read_dat_x_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_x(args);
}
t = clock() - t;
} else if (strcmp(func_name, "y") == 0) {
struct dat_y args = read_dat_y_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_y(args);
}
t = clock() - t;
} else if (strcmp(func_name, "z") == 0) {
struct dat_z args = read_dat_z_from_file(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_z(args);
}
t = clock() - t;
}
// report runtime
double e = ((double)t) / CLOCKS_PER_SEC;
printf("%s: %f %d\n", func_name, e, a);
}
As you can see, in the main function all the statements in each branch of the if-else block are identical; the only difference is that either func_x, func_y, or func_z.
In a functional language, this pattern can be abstract by having a function run_timing_benchmark which takes the func_* and dat_* arguments and hten runs the loop (possibly using polymorphism to define the signature of g). While I can use function pointers in C, I can't write a polymorphic type signature.
What are suggestions for how to reduce the duplication in this program so that the timing code is only defined once? In practice I may have dozens of functions (not just x/y/z) to benchmark using the same code, and the timing code may be more complex.
You can use a macro to generate the code. Since all the structures and functions follow a common naming scheme, you can use token pasting to generate them.
#define PROCESS(suffix, func_name_var, path_var, sum_var, time_var) \
time_var = time();
if(strcmp(func_name_var, #suffix) == 0) { \
struct dat_##suffix args = read_dat_##suffix##_from_file(path_var); \
for (int i = 0; i < 1000; i++) { \
sum_var += func_##suffix(args); \
} \
time_var = time() - time_var;
then you can use it like this:
PROCESS(x, func_name, path, a, t)
else PROCESS(y, func_name, path, a, t)
else PROCESS(z, func_name, path, a, t)
#MarcoBonelli observed correctly in comments that your functions are not quite as similar as they may seem. They have different argument and return types, which is an important distinction in strongly-typed languages such as C. Those functions are not interchangeable in a C-language sense; given that they have different return types, there's not even any function-pointer type that would be compatible with pointers to all the functions.
If you can change the functions then it would be possible to do so in a way that overcomes that limitation. For instance, you could accept the structures to populate as out parameters of type void *:
void read_dat_y_from_file(const char *path, void *args) {
struct dat_y *y_args = (struct dat_y *) args;
// ...
}
// ...
struct dat_y args;
read_dat_y_from_file(path, &args);
You could write a function-pointer-based solution around that.
But a simpler way forward that does not require modifying any functions would be to move the repeated code to a macro:
#define read_and_time(tag) do { \
struct dat_ ## tag args = read_dat_## tag ## _from_file(path); \
t = clock(); \
for (int i = 0; i < 1000; i++) { \
a += func_ ## tag(args); \
} \
t = clock() - t; \
while (0)
With that, you would reduce the if / else chain to
if (strcmp(func_name, "x") == 0) {
read_and_time(x);
} else if (strcmp(func_name, "y") == 0) {
read_and_time(y);
} else if (strcmp(func_name, "z") == 0) {
read_and_time(z);
}
You could even pull a bit more of that into the macro, but I think this form serves clarity best.
One idea could be to make a union to abstract the differences in function signatures and return values. Then build a table of functions and invoke the right one according to the name passed. Something like this: (warning: not tested!)
// struct definitions
struct dat_x {...};
struct dat_y {...};
struct dat_z {...};
// Build a union that contains the structs
union uargs
{
struct dat_x;
struct dat_y;
struct dat_z;
};
// reading structs from a text file (but packaged into the union type)
union uargs read_dat_x_from_file(char *path);
union uargs read_dat_y_from_file(char *path);
union uargs read_dat_z_from_file(char *path);
// functions
int func_x(union uargs dat);
int func_y(union uargs dat);
int func_z(union uargs dat);
struct table_t
{
char *name;
union uargs (*read_dat_fp);
int (*fp)(union uargs dat);
};
// Table of function pointers
struct table_t func_table[]
{
{ "x", read_dat_x_from_file, func_x},
{ "y", read_dat_y_from_file, func_y},
{ "z", read_dat_x_from_file, func_z}
};
// runner computing runtime of func_x, func_y, or func_z
int main(int argc, char** argv) {
char *func_name = argv[1];
char *path = argv[2];
int a;
clock_t t;
for(int i = 0; i < sizeof(func_table) / sizeof(table_t); i++)
{
if(strcmp(func_name, func_table[i].name) == 0)
{
union uargs args = func_table[i].read_dat_fp(path);
t = clock();
for (int i = 0; i < 1000; i++) {
a += func_table[i].fp(args);
}
t = clock() - t;
break;
}
}
// report runtime
double e = ((double)t) / CLOCKS_PER_SEC;
printf("%s: %f %d\n", func_name, e, a);
}
This gets rid of the code duplication and is also somewhat easily scalable.
Another option could be to use some macro magic as in this answer from #Barmar.
Edit: Of course, instead of the union, you could simply use void* and typecasting to pass along pointers to the structs, re-casting them as needed inside the functions. But then you completely throw away all type checking.
The best way would have been to give the functions the same interface. Then you could have created an array of function pointers and gotten quite pretty code.
However, if you are stuck with the functions as they are, the least evil way to reduce code repetition is to use function-like macros. For example by using C11 _Generic:
#define read_dat_from_file(result, path) (result) = \
_Generic((result), \
struct dat_x: read_dat_x_from_file, \
struct dat_y: read_dat_y_from_file, \
struct dat_z: read_dat_z_from_file ) (path);
Where result is a variable of the struct type that you want to store the results inside. Full example:
#include <stdio.h>
struct dat_x { int x; };
struct dat_y { int y; };
struct dat_z { int z; };
struct dat_x read_dat_x_from_file(char *path)
{
puts(__func__);
return (struct dat_x){1};
}
struct dat_y read_dat_y_from_file(char *path)
{
puts(__func__);
return (struct dat_y){2};
}
struct dat_z read_dat_z_from_file(char *path)
{
puts(__func__);
return (struct dat_z){3};
}
#define read_dat_from_file(result, path) (result) = \
_Generic((result), \
struct dat_x: read_dat_x_from_file, \
struct dat_y: read_dat_y_from_file, \
struct dat_z: read_dat_z_from_file ) (path);
int main (void)
{
struct dat_x x;
struct dat_y y;
struct dat_z z;
read_dat_from_file(x, "");
read_dat_from_file(y, "");
read_dat_from_file(z, "");
printf("%d\n", x.x);
printf("%d\n", y.y);
printf("%d\n", z.z);
}
Output:
read_dat_x_from_file
read_dat_y_from_file
read_dat_z_from_file
1
2
3
A not super elegant way, would be to use a function pointer like this:
int (*funcPtr)(void *arg)
And in the implementation of the function you cast the void * to the actual functions argument like struct dat_x *arg = (struct dat_x *)arg

Arrays in c shared library

I want to basically process a struct array in a method in a dynamic library, but when I pass the array and print it (in the exact same manner as in my main program) it has different values.
Consider a struct like this:
struct color {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
}
And the code to print it looks like this:
printf("pos: %p\n", array);
for (i = 0; i < size; i++) {
printf("bgra: %08x\n", ((uint32_t *) array)[i]);
}
Now, what I'm doing in the test program is this:
printf("Table:\n");
print(table, size);
and the output looks like this (as excepted):
pos: 0x7fff5b359530
bgra: 00000000
bgra: ff0000ff
bgra: ff00ffff
But when i execute the same code in a function in the library this is what i get:
pos: 0x7fff5b359530
bgra: 00000008
bgra: 00000030
bgra: 5b3598e0
Now I'm wondering what I'm doing wrong, since i can't see a fault in my code. Also, the values must correlate somehow since, the output is always the same (Except for the address of course).
header.h
#include <stdint.h>
#ifndef __HEADER_H_
#define __HEADER_H_
struct bmpt_color_bgra {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
};
void print(struct bmpt_color_bgra *table, uint8_t size);
uint8_t *gen(struct bmpt_color_bgra *table, uint8_t size);
#endif
library.c
#include <stdlib.h>
#include <stdio.h>
#include "header.h"
#define EXPORT __attribute__((visibility("default")))
__attribute__((constructor))
static void initializer(void) {
printf("[%s] initializer()\n", __FILE__);
}
__attribute__((destructor))
static void finalizer(void) {
printf("[%s] finalizer()\n", __FILE__);
}
EXPORT
void print(struct bmpt_color_bgra *table, uint8_t size) {
uint8_t i;
printf("pos: %p\n", table);
for (i = 0; i < size; i++) {
printf("bgra: %08x\n", ((uint32_t *) table)[i]);
}
}
EXPORT
uint8_t *gen(struct bmpt_color_bgra *table, uint8_t size) {
printf("table in func:\n");
print(table, size);
}
test.c
#include <stdio.h>
#include <stdlib.h>
#include "header.h"
int main(int argc, char **argv) {
struct bmpt_color_bgra arr[3];
struct bmpt_color_bgra c;
c.b = 0x0;
c.g = 0x0;
c.r = 0x0;
c.a = 0x0;
arr[0] = c;
c.b = 0xff;
c.a = 0xff;
arr[1] = c;
c.r = 0xff;
arr[2] = c;
//the first result (the correct one)
print(arr, 3);
//the second result
gen(arr, 3);
}
This probably comes down to memory alignment of the members within the struct, and the size of the struct itself differing between your program and the dynamic/shared library. You don't mention which compiler you are using, but using different compiler(s) or compiler options for your program and the shared library could cause this effect.
You can preserve binary compatibility between modules by specifying exactly how the members of the struct should be aligned. E.g in GCC you can force how the struct is represented in memory by use of an attribute.
See https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Type-Attributes.html for GCC alignment instructions
struct bmpt_color_bgra {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
} __attribute__ ((packed));
Also take a look at Byte Alignment for integer (or other) types in a uint8_t array for a similar question.

Categories

Resources