0

The problem is that due to some unavoidable reasons I need to maintain 2 copy of same structure in a C code. Is there a way I can add some compiler check to make sure if someone changes (adds/deletes/modifies) one of the structure that person should also update the copy ?

The two solutions I can think of are :

  1. I can add a comment as a request to whoever makes changes (Very unreliable)
  2. I can use offsetof() for fields as a runtime check

But I am looking for something which can assure this during compilation.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
adikshit
  • 205
  • 3
  • 10
  • 3
    Please specify your unavoidable reasons. There's no good way to do exactly what you want, (you could kludge it with `static_assert` and a bunch of offsetof/sizeof checks, but it wouldn't be perfect) but there might be a better way to solve your larger problem. – zwol Sep 09 '14 at 20:39
  • 1
    `offsetof` works during compilation. Do you need something suitable for use in a preprocessor directive? I think, that's impossible. – mafso Sep 09 '14 at 20:40
  • 3
    Can you elaborate on the unavoidable reasons that make you have two separate copies? If you could figure out some way to only use one class definition, your entire problem is implicitly solved. – millinon Sep 09 '14 at 20:54
  • Code a compare into your build process? Though I agree with the others that if this is supposed to be the same datatype there should never be a reason that you have to maintain two copies -- appropriate includes and a bit of refactoring ought to solve it. – keshlam Sep 09 '14 at 23:17
  • @Zack and millnon I would not like to go into details of why but you can consider this as a hypothetical situation and suggest if there is any intelligent way of doing this stupidity :) I understand this is not a very good coding practice but I am not looking for some "ultimate solution" as small hacks would be good enough for me. Can you elaborate on how offsetof will work during compilation – adikshit Sep 09 '14 at 23:25
  • Can you elaborate on how it should work during run-time? :) The compiler knows the information necessary to calculate the offsets (just like `sizeof`). This information typically isn't available at run-time in C. Btw, I also think that's an XY problem and would appreciate an example where this may be desirable (and you're right, that information isn't necessary to answer the question, but only to determine its usefulness). – mafso Sep 11 '14 at 10:24
  • You can notify people by preceding their name with `@`. I only saw your message by chance. – mafso Sep 11 '14 at 10:27

3 Answers3

0

There is no perfect way.

You can use a static assert macro like found in C compiler asserts - how to implement?

and then assert the sizeof each struct is the same. But that doesn't mean they are identical.

Possibly the better way is to add some code generation in so that part of the build you generate the copy from the original.

But ultimately something is wrong when you have to duplicate something rather than re-use.

Community
  • 1
  • 1
Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
0

Only allow struct doublestruct * and global supporting functions like ds_foo(struct doublestruct *, ...) to be visible to the rest of code. Then file ds.c can control all access to and from struct doublestruct and maintain a redundant copy.

// ds.h
struct doublestruct *ds_Init();
void ds_setA(struct doublestruct *ds, int A);
int ds_getA(const struct doublestruct *ds);


// ds.c
struct doublestruct {
  int A;
  double B;
  char C;
};

#include <stdlib.h>

struct doublestruct * ds_Init() {
  struct doublestruct *p = malloc(sizeof *p *2);
  if (p) memset(p, 0, sizeof *p * 2);
  return p;
}

void ds_setA(struct doublestruct *ds, int A) {
  ds[0].A = A;
  ds[1].A = A;
}

int ds_getA(const struct doublestruct *ds) {
  if (ds[0].A != ds[1].A) exit(-1);  // Memory failure
  return ds[0].A;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

I think the right way to cope with this situation is to make some kind of signature to the structure definition and check it at make time so you can check for modifications.

  1. first, mark the structures of this type, so you can access to them easily: something like '_some_tag_' #define'd as nothing in some header allows you to search for it automatically.
  2. then, use some kind of development tool to parse the fields, canonicalyze them and make some kind of hash function as a result.
  3. register this signature for future compilations and warn the compiling team of a structure change.

Think, you had better to be overcomplaint than under, so in case of structure modification you'll get at least one indication.

Suppose you have:

struct A { bla bla bla };

and then you modify it to be:

#include <somefile where you have defined macro ___hash_protected___>
/* #define ___hash_protected___ */
...
struct ___hash_protected___ A { bla bla bla };

now, write a program that searches for that tag, computes the signature of structure A and checks it with the value stored in a database file. It must do two things: first compute the hash value of the structure, then compare it with the saved one and warn if they differ. If structure is new, just add the hash value to the database.

I you want to protect it from unauthorized use, just use a cryptographic secure hash function (e.g. SHA256) and protect it with some secret string prepended.

Of course, you'll have to parse at least the structure definition to be able to calculate a valid hash.

but, REMEMBER, you had better to define it in a common include file, than to define it twice. I know there are cases in which a define file has to be distributed to be used at several places, leading to possible different versions of it.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31