tags:

views:

263

answers:

4

Can you define a macro that accesses a normal variable, but in a read-only fashion (other than defining it as a call to a function)? For example, can the VALUE macro in the following code be defined in such a way that the dostuff() function causes a compile error?

struct myobj {
  int value;
}

/* This macro does not satisfy the read-only requirement */
#define VALUE(o) (o)->value

/* This macro uses a function, unfortunately */
int getvalue(struct myobj *o) { return o->value; }
#define VALUE(o) getvalue(o)

void dostuff(struct myobj *foo) {
   printf("The value of foo is %d.\n", VALUE(foo)); /* OK */
   VALUE(foo) = 1; /* We want a compile error here */
   foo->value = 1; /* This is ok. */
}
+6  A: 

If the variable is always numeric, this works:

#define VALUE(x) (x+0)

or in the context of your example,

#define VALUE(x) (x->value+0)
Mark Ransom
Thanks, this seems to be the most concise working answer
Joshua Swink
+2  A: 

Try

#define VALUE(o) (const int)((o)->value)
Andrew Stein
That works in C++ but not C (tested with gcc 3.4.4)
Hugh Allen
Works in gcc 4.1...
Greg Rogers
+6  A: 

Ok, I came up with one:

#define VALUE(o) (1 ? (o)->value : 0)
Joshua Swink
I like yours too, because it works on non-numeric values just as easily.
Mark Ransom
Actually it may not, I think the type of data on both sides of the colon must be the same in the tertiary operator. So if o->value is a struct, for example, I don't think this would work. You could put (o)->value on both sides of the colon though.
Kip
A: 

Is this a puzzle or is it an engineering task? If it's an engineering task, then there are better ways to get opacity of structures in C. In this blog article, I wrote a decent enough description of how to do that in C.

plinth
It looks effective, but I was looking for something more quick-n-dirty. I have a specific application in mind for this. It won't be as rock solid as a managed library, but there is limited time for development.
Joshua Swink
It's not so much the managed/unmanaged bit, it's the public opaque struct and API combined with a private open struct. This is the standard C trick to hide data to a client of an API. If you're using C++ you would obviously use a class.
plinth