How do I dump an arbitrary struct in C? - c

I don't know which direction to go,perhaps something like reflection will help?

If you're using Clang 8 or newer, you can now use the built-in compiler function __builtin_dump_struct to dump a struct. It uses the information that's naturally available at compile time to generate code that pretty-prints a struct.
Example code demonstrating the function:
dumpstruct.c:
#include <stdio.h>
struct nested {
int aa;
};
struct dumpme {
int a;
int b;
struct nested n;
};
int main(void) {
struct nested n;
n.aa = 12;
struct dumpme d;
d.a = 1;
d.b = 2;
d.n = n;
__builtin_dump_struct(&d, &printf);
return 0;
}
Example compile-and-run:
$ clang dumpstruct.c -o dumpstruct
$ ./dumpstruct
struct dumpme {
int a : 1
int b : 2
struct nested n : struct nested {
int aa : 12
}
}
If you're not using Clang >= 8 but you are using GCC, it's pretty easy to switch. Just install the clang-8 or clang-9 package and replace invocations of gcc with clang.

The answer of #Kerrek SB works realy well, I just post how to use it in a function using a void pointer.
int dump(void *myStruct, long size)
{
unsigned int i;
const unsigned char * const px = (unsigned char*)myStruct;
for (i = 0; i < size; ++i) {
if( i % (sizeof(int) * 8) == 0){
printf("\n%08X ", i);
}
else if( i % 4 == 0){
printf(" ");
}
printf("%02X", px[i]);
}
printf("\n\n");
return 0;
}
int main(int argc, char const *argv[])
{
OneStruct data1, data2;
dump(&data1, sizeof(OneStruct));
dump(&data2, sizeof(OneStruct));
return 0;
}

Here's a hex dump, about as general as you can get:
struct Foo x;
unsigned int i;
const unsigned char * const px = (unsigned char*)&x;
for (i = 0; i < sizeof(x); ++i) printf("%02X ", px[i]);
Note that the result of this is entirely implementation-defined; presumably there'll be plenty of padding, and you won't know what any of the printed values mean. (Most of them will probably just be pointers to some other part of space.)
As Etienne says, C is a statically typed language and does not have reflection, so you have to know the declaration of Foo in order to interpret the content of x.

What do you want to do with your file once you've got it? If it's going to be read back in at a later time just use fread and fwrite, like
struct foo * bar;
fwrite(bar,sizeof(*bar),1,stdout);
...
fread(bar,sizeof(*bar),1,stdin);
This will give binary output that's dependant on your compiler/platform, as long as those are unchanged you should be fine. From there you can also feed the file into a hex reader etc., though you'll need to know the layout of the struct to do anything useful with it.

Related

Function pointer as "tag" in tagged union

One of the reasons why I tend to avoid using tagged unions is that I don't like the idea of the performance penalty that the switch/case statement for the tag might introduce if the number of tags is greater than 4 or so.
I just had the idea that instead of using a tag, one could set a pointer to a function that reads the last written value in the union. For example:
union u{
char a;
int b;
size_t c;
};
struct fntag{
void (*readval)(union u *ptr, void *out);
union u val;
};
And then, whenever you write a value into val, you also update the readval pointer accordingly, so that it points to a function that reads the last field you wrote in the union. Yes, there's a difficult issue, and it's where to return the read value (because the same function pointer cannot point to functions returning different types). I chose to return the value through a pointer to void so that such function can also be "overloaded" with C11 _Generic() and thus casting and writing into different types for the output.
Of course, invoking a pointer to a function has a performance overhead, and I guess it's far heavier that checking the value of an enum, but at some point, if the number of tags is big, I believe it would be faster than switch/case.
My question is: Have you ever seen this technique used somewhere? (I haven't, and I don't know if it's because real world application of this would require _Generic() on the readval function, which requires C11, or if it's because of some problem I'm not noticing at this moment). How many tags do you guess you'd need to have for the pointer to function being faster -in current Intel CPUs- than the switch/case?
You could do that. In your case a more optimization friendly function signature would be size_t size_t (*)(union u U) (all the union values can be sort of fitted into size_t and the union is small enough for passing by value to be more efficient), but even with that, function calls have non-negligible overhead that tends to be significantly larger than that of a jump through a switch-generated jump table.
Try something like:
#include <stddef.h>
enum en { e_a, e_b, e_c };
union u{
char a;
int b;
size_t c;
};
size_t u_get_a(union u U) { return U.a; }
size_t u_get_b(union u U) { return U.b; }
size_t u_get_c(union u U) { return U.c; }
struct fntag{ size_t (*u_get)(union u U); union u u_val; };
struct entag{ enum en u_type; union u u_val; };
struct fntag fntagged1000[1000]; struct entag entagged1000[1000];
void init(void) {
for (size_t i=0; i<1000; i++)
switch(i%3){
break;case 0:
fntagged1000[i].u_val.a = i, fntagged1000[i].u_get = &u_get_a;
entagged1000[i].u_val.a = i, entagged1000[i].u_type = e_a;
break;case 1:
fntagged1000[i].u_val.b = i, fntagged1000[i].u_get = &u_get_b;
entagged1000[i].u_val.b = i, entagged1000[i].u_type = e_b;
break;case 2:
fntagged1000[i].u_val.c = i, fntagged1000[i].u_get = &u_get_c;
entagged1000[i].u_val.c = i, entagged1000[i].u_type = e_c;
}
}
size_t get1000fromEnTagged(void)
{
size_t r = 0;
for(int i=0; i<1000; i++){
switch(entagged1000[i].u_type){
break;case e_a: r+=entagged1000[i].u_val.a;
break;case e_b: r+=entagged1000[i].u_val.b;
break;case e_c: r+=entagged1000[i].u_val.c;
/*break;default: __builtin_unreachable();*/
}
}
return r;
}
size_t get1000fromFnTagged(void)
{
size_t r = 0;
for(int i=0; i<1000; i++) r += (*fntagged1000[i].u_get)(fntagged1000[i].u_val);
return r;
}
int main(int C, char **V)
{
size_t volatile r;
init();
if(!V[1]) for (int i=0; i<1000000; i++) r=get1000fromEnTagged();
else for (int i=0; i<1000000; i++) r=get1000fromFnTagged();
}
At -O2, I'm getting more then twice the performance in the switch-based code.

Structs and passing values to them

If i had an array such as int numbers[5] i could assign values to it with numbers[0] = 1 or numbers[3] = 4. Then if i had a struct such as
struct structName
{
int number0;
int number1;
int number2;
};
is there any way to do something like the following (note this is not working code)
int main(void)
{
struct structName name; //how could i declare this to do the following
for(int i = 0; i < 2; i++)
{
name[i] = i; //maybe name.[i]
}
}
so is there a way to write name[ variable ] = someNumber to assign someNumber to say number0 (if variable was 0) or number2 (if variable was 2). ive been looking for days and cant find anything that does this. (maybe i just don't know what to look for)
is there any way to do something like the following
No, there's no way to access the fields of the structure by index. You use the names of the fields instead:
struct structName name;
name.number0 = someNumber;
name.number1 = someOtherNumber;
If you want to access the values by index, use an array instead, even if it's embedded in the structure:
struct structName
{
int numbers[3];
// other fields here
};
Then you can say:
struct structName name;
for (int i = 0; i <= 2, i++) {
name.numbers[i] = i;
}
You could write a function which uses a switch statement that allows you to access fields by index. Something like:
#include<stdio.h>
struct structName{
int number0;
int number1;
int number2;
};
void assign(struct structName * name, int i, int j){
switch(i){
case 0:
name->number0 = j;
break;
case 1:
name->number1 = j;
break;
case 2:
name->number2 = j;
break;
}
}
int main(void){
int i;
struct structName name;
for(i = 0; i <= 2; i++){
assign(&name,i,i);
}
//test:
printf("%d\n",name.number0);
printf("%d\n",name.number1);
printf("%d\n",name.number2);
return 0;
}
(which prints 0,1,2 as expected).
Needless to say, there isn't much point in doing this (as opposed to just having a field which is an array) unless the struct in question is already defined as part of an API or already part of a code base which isn't easily refactored.
Yes, with some weird and inadvisable memory manipulation. You're much better off using an array.
struct structName
{
int numbers[3];
};
int main(void)
{
struct structName name;
for(int i = 0; i <= 2; i++)
{
name.numbers[i] = i;
}
}
Also note that you had some syntax errors in your for loop and an off-by-one error.
Macros with arguments should work
#define name(x) x
So name(1) would become 1. name(2) would become 2 and so on.
In C, there is no spoon.
struct structName name;
int *idx = &name; // First we need a memory address to the struct
for (int i = 0; i < sizeof(name) / sizeof(*idx); ++i) {
// idx[i] == name.numberX
idx[i] = i;
}
Now, if you check the values of name.number0, name.number1, name.number2 you will see they contain the correct values.
This is not a very good way of doing things with structs, but I felt compelled to answer after the top response claims it is impossible.

memcpy() and memmove() not working as expected

I ran into this problem while working with a struct array within a struct. I'm trying to set the entry array in the dict using memcpy. I'm getting a mixture of the expected values and some seemingly random integers as output.
Oddly enough, I tried this code with some online compilers, and it worked fine. I thought that it might have to do with overlapping memory regions, so I tried memmove() but the result was the same.
I think I might be using malloc improperly for the dict, but I'm not sure. It seems I can't use malloc for the internal array, or for the individual elements. I'd appreciate any help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int i;
} entry;
typedef struct{
entry e[10];
int i;
} dict;
dict* d;
void test(dict* di){
printf("%d\n", di->i);
int k;
for (k = 0; k < 10; k ++){
printf(("%d\n"),di->e[k].i);
}
}
int main(){
entry en[10];
d = malloc(sizeof(d));
int k;
for (k = 0; k < 10; k++){
en[k].i = k;
}
d->i = 50;
memcpy(d->e, en, 10*sizeof(entry));
test(d);
return 0;
}
d = malloc(sizeof(d));
d is a dict*; sizeof d is sizeof(dict*). Looks like you meant sizeof *d.

C- Iterating over an array of structs passed through a void*

I have a function
struct Analysis reduce (int n, void* results)
Where n is the number of files to be analyzed, and I'm passing an array of Analysis structs to results.
The Analysis struct is defined as follows:
struct Analysis {
int ascii[128]; //frequency of ascii characters in the file
int lineLength; //longest line in the file
int lineNum; //line number of longest line
char* filename;
}
I've cast the void * as such,
struct Analysis resArray[n];
struct Analysis* ptr = results;
resArray[0] = ptr[0];
but I can't figure out how to iterate through the resArray properly. I've tried
for (i = 0; i < n; i++){
printf("lineLength: %d\n", resArray[i].lineLength);
}
with n = 3, and I'm getting garbage values. resArray[0] is correct, but resArray[1] is an insanely high number and resArray[2] is just 0. Why wouldn't resArray[1] or resArray[2] give the correct values? If I was incrementing the address incorrectly then it would make sense but I'm just accessing the array at a certain index. Pretty lost here!
resArray[0] is correct because there is "something":
resArray[0] = ptr[0];
Other elements are garbage because you didn't set there any values. If you want to copy entire array you need to change copying method to:
for (i = 0; i < n; i++)
{
resArray[i] = ptr[i];
}
You can't assign a pointer to an array directly because they are different typessince array[n] is type struct analysis(*)[n] and ptr is type struct analysis(*). Check here for more info.
Hopefully this code will help you.
#include <stdio.h>
#define d 3
struct Analysis {
int ascii[128];
int lineLength;
int lineNum;
char *filename;
};
struct Analysis Analyses[d];
struct Analysis reduce(int n, void *results) {
struct Analysis resArray[n];
struct Analysis *ptr = results;
for (int i = 0; i < n; i++) {
resArray[i] = ptr[i];
}
for (int i = 0; i < n; i++) {
printf("lineLength: %d\n", ptr[i].lineLength);
}
return *ptr;
}
int main(void) {
struct Analysis a = {{5}, 2, 2, "George"};
struct Analysis b = {{6}, 3, 3, "Peter"};
struct Analysis c = {{7}, 4, 4, "Jane"};
Analyses[0] = a;
Analyses[1] = b;
Analyses[2] = c;
reduce(d, &Analyses);
return 0;
}
You can try it online.

Random matrix struct creation

I'm trying to make a struct that generates a random matrix and am getting "error: expected â=â, â,â, â;â, âasmâ or â_attribute_â before âmatrixâ" when compiling. How can I get this to work effectively and efficiently?
I guess expected errors usually are caused by typos but I don't see any.
I'm very new to C so pointers and malloc are quite foreign to me. I really appreciate your help.
/* It's called RandomMatrixMaker.c */
#include <stdio.h>
#include <stdlib.h>
typdef struct {
char* name;
int MID;
int MRows;
int MCols;
long[][]* MSpace;
} matrix;
matrix makeRIDMatrix(char* name, int MID, int MRows, int MCols) {
matrix m;
static int i, j, r;
m.name = name;
m.MID = MID;
m.MRows = MRows;
m.MCols = MCols;
for (i=0; i<m.MRows; i++) {
for (j=0; i<m.MCols; j++) {
r = random(101);
*(m.MSpace[i][j]) = r;
}
}
return m;
}
int main(void) {
makeRIDMatrix("test", 1, 10, 10);
return 0;
}
There is indeed a typo. You misspelled typedef:
typdef struct {
should be:
typedef struct {
EDIT:
Also, there's no reason to use static here:
static int i, j, r;
You can just get rid of the static modifier.
int i, j, r;
As another poster mentioned, there's a typo, but even with that corrected, it wouldn't compile, due to the definition of matrix.MSpace.
Let's begin in makeRIDMatrix(). You've declared an automatic (stack) variable of type "matrix". At the end of the function, you return that object. Whilst this is permissible, it's not advisable. If the struct is large, you will be copying a lot of data unnecessarily. Better to pass a pointer to a matrix into makeRIDMatrix(), and have makeRIDMatrix() fill in the contents.
The test in the inner loop is against i, but should be against j.
Next, let's look at the definition of "matrix". The definition of "MSpace" is a mess, and wouldn't even compile. Even if it did, because you haven't defined the length of a row, the compiler would not be able to calcuate the offset to any given item in the array. You want a two-dimensional array without giving the row length, but you can't do that in C. You can in other languages, but not C.
There's a lot more I could point out, but I'd be missing the real point. The real point is this:
C Is Not Java.
(It's also not one of the interpreted languages such as JavaScript, PHP, Python, Ruby and so on.)
You don't get dynamically-expanding arrays; you don't get automatic allocation of memory; you don't get garbage collection of unreferenced memory.
What you need is something more like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
char* name;
int MID;
unsigned int MRows;
unsigned int MCols;
long *MSpace;
} matrix;
void makeRIDMatrix(matrix *pmx, char* name, int MID,
unsigned int MRows, unsigned int MCols) {
int i, j;
long *MSpace = malloc(sizeof(*MSpace)*MRows*MCols);
if (MSpace == NULL) {
return;
}
pmx->name = name;
pmx->MID = MID;
pmx->MRows = MRows;
pmx->MCols = MCols;
pmx->MSpace = MSpace;
srandom((unsigned int)time(NULL));
for (i=0; i<MRows; i++) {
for (j=0; i<MCols; j++) {
long int r = random() % 101L;
*(MSpace++) = r;
}
}
}
inline long * item_addr(const matrix *pmx,
unsigned int row, unsigned int col) {
if (pmx == NULL || pmx->MSpace == NULL
|| row >= pmx->MRows || col >= pmx->MCols) {
return NULL;
}
return &(pmx->MSpace[row * pmx->MCols + col]);
}
long get_item(const matrix *pmx, unsigned int row, unsigned int col) {
long *addr = item_addr(pmx, row, col);
return addr == NULL ? 0L : *addr;
}
void set_item(matrix *pmx,
unsigned int row, unsigned int col,
long val) {
long *addr = item_addr(pmx, row, col);
if (addr != NULL) {
*addr = val;
}
}
int main(void) {
matrix m;
makeRIDMatrix(&m, "test", 1, 10, 10);
return 0;
}
Note a few things here. Firstly, for efficiency, I fill the array as if it were one-dimensional. All subsequent get/set of array items should be done through the getter/setter functions, for safety.
Secondly, a hidden nasty: makeRIDMatrix() has used malloc() to allocate the memory - but it's going to be job of the calling function (or its successors) explciitly to free() the allocated pointer when it's finished with.
Thirdly, I've changed the rows/cols variables to unsigned int - there's little sense in definining an array with negative indices!
Fourthly: little error checking. For example, makeRIDMatrix() neither knows nor cares whether the parameter values are sensible (e.g. the matrix pointer isn't checked for NULLness). That's an exercise for the student.
Fifthly, I've fixed your random number usage - after a fashion. Another exercise for the student: why is the way I did it not good practice?
However - all of this is moot. You need to get yourself a good C textbook, or a good online course, and work through the examples. The code you've given here shows that you're punching above your weight at the moment, and you need to develop some more C muscles before going into that ring!
In relation to your question about "variable sized arrays", you could have something like:
/* can stick this into your struct, this is just an example */
size_t rows, cols;
long **matrix;
/* set the values of rows, cols */
/* create the "array" of rows (array of pointers to longs) */
matrix = (long**)malloc(rows * sizeof(long*));
/* create the array of columns (array of longs at each row) */
for (i = 0; i < rows; i++)
matrix[i] = (long*)malloc(cols * sizeof(long));
/* ... */
/* free the memory at the end */
for (i = 0; i < rows; i++)
free(matrix[i]);
free(matrix);
Then you can just access the dynamically allocated matrix similar to any other array of arrays.
ie. to set element at the first row (row 0) and fourth column (column 3) to 5:
matrix[0][3] = 5;

Resources