1

I came across this simple program somewhere

#include<stdio.h>
#include<stdlib.h>

char buffer[2];
struct globals {

  int value;
  char type;
  long tup;

};

#define G (*(struct globals*)&buffer)

int main ()
{
        G.value = 233;
        G.type = '*';
        G.tup = 1234123;

        printf("\nValue = %d\n",G.value);
        printf("\ntype = %c\n",G.type);
        printf("\ntup = %ld\n",G.tup);

        return 0;
}

It's compiling (using gcc) and executing well and I get the following output:

Value = 233
type = *
tup = 1234123

I am not sure how the #define G statement is working. How G is defined as an object of type struct globals ?

2
  • 2
    Your buffer is too small, its length should be at least sizeof(struct globals). Commented Apr 28, 2014 at 10:19
  • @user28264 There is a well written and thorough answer provided. You should mark it as accepted if it answered your question or give more information on the problem/tell why it isn't sufficient. Otherwise it will remain as unanswered since no answers have been accepted. Commented Jul 15, 2014 at 13:18

2 Answers 2

4

First, this code has undefined behavior, because it re-interprets a two-byte array as a much larger struct. Therefore, it is writing past the end of the allocated space. You could make your program valid by using the size of the struct to declare the buffer array, like this:

struct globals {
    int value;
    char type;
    long tup;    
};
char buffer[sizeof(struct globals)];

The #define is working in its usual way - by providing textual substitutions of the token G, as if you ran a search-and-replace in your favorite text editor. Preprocessor, the first stage of the C compiler, finds every entry G, and replaces it with (*(struct globals*)&buffer).

Once the preprocessor is done, the compiler sees this code:

int main ()
{
    (*(struct globals*)&buffer).value = 233;
    (*(struct globals*)&buffer).type = '*';
    (*(struct globals*)&buffer).tup = 1234123;

    printf("\nValue = %d\n",(*(struct globals*)&buffer).value);
    printf("\ntype = %c\n",(*(struct globals*)&buffer).type);
    printf("\ntup = %ld\n",(*(struct globals*)&buffer).tup);

    return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

1

The macro simply casts the address of the 2-character buffer buf into a pointer to the appropriate structure type, then de-references that to produce a struct-typed lvalue. That's why the dot (.) struct-access operator works on G.

No idea why anyone would do this. I would think it much cleaner to convert to/from the character array when that is needed (which is "never" in the example code, but presumably it's used somewhere in the larger original code base), or use a union to get rid of the macro.

union {
  struct {
   int value;
   /* ... */
  } s;
  char c[2];
} G;

G.s.value = 233;  /* and so on */

is both cleaner and clearer. Note that the char array is too small.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.