Take the 2-minute tour ×

Is it possible to see what is going on behind gcc and g++ compilation process?
I have the following program:

#include <stdio.h>
#include <unistd.h>

size_t sym1 = 100;
size_t *addr = &sym1;

size_t *arr = (size_t*)((size_t)&arr + (size_t)&addr);

int main (int argc, char **argv)
    (void) argc;
    (void) argv;

    printf("libtest: addr of main(): %p\n", &main);
    printf("libtest: addr of arr: %p\n", &arr);

    return 0;

Why is it possible to produce the binary without error with g++ while there is an error using gcc?
I'm looking for a method to trace what makes them behave differently.

# gcc test.c -o test_app
test.c:7:1: error: initializer element is not constant
# g++ test.c -o test_app

I think the reason can be in fact that gcc uses cc1 as a compiler and g++ uses cc1plus.
Is there a way to make more precise output of what actually has been done?
I've tried to use -v flag but the output is quite similar. Are there different flags passed to linker?
What is the easiest way to compare two compilation procedures and find the difference in them?

share|improve this question
Because C!=C++. –  BoBTFish Nov 27 '13 at 14:47
One of the reason is that they link to different libraries. –  WiSaGaN Nov 27 '13 at 14:47
Because gcc compiles c code and g++ compiles c++ code, those are similiar but still different languages. Im not an expert, but my guess would simply be that the thing you tried there (assigning a none constant to a global) is simply not possible in c. –  Paranaix Nov 27 '13 at 14:47
Please see the actual question in topic (not only the headline) :-) I want to know some way to output what going on during compilation. What subprograms are used, what flags passed to them, what libraries are linked... I want to see some background... –  Mikhail Kalashnikov Nov 27 '13 at 14:51
@MikhailKalashnikov Add the -v flag to gcc or g++ –  nos Nov 27 '13 at 19:17

2 Answers 2

up vote 10 down vote accepted

In this case, gcc produces nothing because your program is not valid C. As the compiler explains, the initializer element (expression used to initialize the global variable arr) is not constant.

C requires initialization expressions to be compile-time constants, so that the contents of local variables can be placed in the data segment of the executable. This cannot be done for arr because the addresses of variables involved are not known until link time and their sum cannot be trivially filled in by the dynamic linker, as is the case for addr1. C++ allows this, so g++ generates initialization code that evaluates the non-constant expressions and stores them in global variables. This code is executed before invocation of main().

Executables cc1 and cc1plus are internal details of the implementation of the compiler, and as such irrelevant to the observed behavior. The relevant fact is that gcc expects valid C code as its input, and g++ expects valid C++ code. The code you provided is valid C++, but not valid C, which is why g++ compiles it and gcc doesn't.

share|improve this answer
Since 2011 it's not valid C++ either, because of that while(1);. –  BoBTFish Nov 27 '13 at 14:49
Ah, but it would be good to say why the initializer expression is not a constant expression, and that is because the addresses involved are not known until link time. In C++, I believe the compiler outputs what amounts to a mini-constructor for this case. (Not exactly a constructor, but commonly uses the constructor mechanism to run.) –  Joe Z Nov 27 '13 at 14:50
But why there is no error about "addr" variable? Address of "sym1" not known until link time as well, isn't it? Why gcc can compile "int addr = &sym1", but can not "int addr = &sym1 + &sym2"? (and why g++ can compile the both?) –  Mikhail Kalashnikov Nov 27 '13 at 14:56
@MikhailKalashnikov the answer to the last question is that the compiler has to put instructions in the object file for the linker to follow to put the right address in the right right place at link time These instructions (called relocations) have a very simple format and probably can't do addition. (By the way I used "instructions" in its generic sense, not related to "instructions of the CPU architecture") –  Wumpus Q. Wumbley Nov 27 '13 at 15:14
@user4815162342 : BTW, I found the other relevant bit in C99 which makes the expression from the OP illegal in 6.6, paragraph 6: "An integer constant expression shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator." –  Joe Z Nov 27 '13 at 22:08

There is a slightly more interesting question lurking here. Consider the following test cases:

#include <stdint.h>

#if TEST==1
void *p=(void *)(unsigned short)&p;
#elif TEST==2
void *p=(void *)(uintptr_t)&p;
#elif TEST==3
void *p=(void *)(1*(uintptr_t)&p);
#elif TEST==4
void *p=(void *)(2*(uintptr_t)&p);

gcc (even with the very conservative flags -ansi -pedantic-errors) rejects test 1 but accepts test 2, and accepts test 3 but rejects test 4.

From this I conclude that some operations that are easily optimized away (like casting to an object of the same size, or multiplying by 1) get eliminated before the check for whether the initializer is a constant expression.

So gcc might be accepting a few things that it should reject according to the C standard. But when you make them slightly more complicated (like adding the result of a cast to the result of another cast - what useful value can possibly result from adding two addresses anyway?) it notices the problem and rejects the expression.

share|improve this answer
Yeah, looks reasonable.. –  Mikhail Kalashnikov Nov 27 '13 at 15:25

Your Answer


