11

In C, if I make a variable and print its address like this:

int a;
int main (void) {
    printf ("%p", &a);
    return 0;
}

The output was: 00AA

The same program in C++ using the line:

cout << &a << endl;

The output was: 0x8f970aa

What is the difference between these two?

I compiled both the programs using Turbo C.

senshin
  • 10,022
  • 7
  • 46
  • 59
Developer101
  • 217
  • 3
  • 8
  • 9
    c++ likes the `0x8f970` ... – Iharob Al Asimi Mar 27 '15 at 15:08
  • 29
    The difference is precisely `0x8f97000`. Seriously though, were you expecting different compilers to store variables in exactly the same places? – r3mainer Mar 27 '15 at 15:09
  • 1
    You might expect it to vary from run to run using the same binary if your OS has a feature like [ASLR](http://en.wikipedia.org/wiki/Address_space_layout_randomization). – Brian Cain Mar 27 '15 at 15:10
  • 7
    You should technically be casting that to `void*` for `printf`. – chris Mar 27 '15 at 15:11
  • 3
    Are you asking about the output or about its format? –  Mar 27 '15 at 15:17
  • 6
    The C99 standard has this to say about the `p` format descriptor: "The value of the pointer is converted to a sequence of printing characters, *in an implementation-defined manner*" (emphasis added). Even though you compile both programs with Turbo C, and even if the variable is laid out at the same relative address both ways, there is no particular reason why the two should produce the same output. At a guess, though, the C version is printing an offset from the program's load address, rather than an absolute address. – John Bollinger Mar 27 '15 at 15:17
  • @chris As far as I know, there is no need for that with `printf`. The size of `void*` and `int*` are equal. – Lingxi Mar 27 '15 at 15:19
  • 2
    I suspect a small memory model with the C compilation and a large memory model was used with C++. Post your compiler options for both. – chux - Reinstate Monica Mar 27 '15 at 15:20
  • 4
    @Lingxi, *If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.* (C99 §7.19.6.1/9). %p says *The argument shall be a pointer to void.* – chris Mar 27 '15 at 15:21
  • @chris Well, that is true, technically. I guess I'm just not that much of a language lawyer :) – Lingxi Mar 27 '15 at 15:26
  • 1
    @Lingxi, the standard does not guarantee that the sizes of `void*` and `int*` are equal, though I am unaware of any implementation where it is not the case. What the standard requires is that "A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer." This requires that `void*` be at least as large as `int*`, but does not prevent `void*` from being larger. – John Bollinger Mar 27 '15 at 15:29
  • The following code change will fix it. int *a; a = 0x00aa; If you print it now it will be the same in both languages... ;-) – AnthonyLambert Mar 27 '15 at 15:29
  • @chris Also, the bit pattern may change after the conversion if the source pointer has a null pointer value. The standard does not guarantee the null pointer values of `int*` and `void*` to be the same. – Lingxi Mar 27 '15 at 15:33
  • @AnthonyLambert `0x00aa` is of type `int`, which is not implicitly convertible to `int*`. So `a = 0x00aa` won't compile. – Lingxi Mar 27 '15 at 15:36
  • @chris It seems that `void*` and `int*` are required to be of the same size. See http://en.cppreference.com/w/cpp/language/static_cast. At (10), it says "A prvalue of type pointer to void (possibly cv-qualified) can be converted to pointer to any type. If the value of the original pointer satisfies the alignment requirement of the target type, `then the resulting pointer value is unchanged`, otherwise it is unspecified.". – Lingxi Mar 27 '15 at 15:42
  • 1
    "The output as : 0x8f970aa" is maybe missing an 8th digit. Please confirm only 7 hex digits were printed. Also: still confident code is using different memory models. – chux - Reinstate Monica Mar 27 '15 at 16:10
  • @Lingxi , Read [`printf("%p")` and casting to `(void *)`](http://www.stackoverflow.com/questions/24867814/printfp-and-casting-to-void) – Spikatrix Mar 27 '15 at 16:20
  • Also, your are missing `"\n"` for the `printf` call. Perhaps part of your output is stuck in a buffer. – Jens Gustedt Mar 27 '15 at 16:45
  • I use GNU's compiler and get *almost* the same addesses in *exactly* the same format, namely 0x601044 and 0x601194. The differnce is merely due to a slightly different memory layout. So what you see is vompiler dependent (and the compiler differences between Turbo C and Turbo C++ seem to matter). - What is the memory model (tiny, small, large, ...) that your C uses anyway (assuming Intel compatible CPU)? – Hagen von Eitzen Mar 27 '15 at 17:02
  • Turbo C? That's kind of ancient - it looks like you compiled the C program in a segmented mode with 16 bit near pointers - that's why you only get 4 hex digits for the address. – Stefan Atev Mar 27 '15 at 17:58
  • I'm throwing in a round of address space layout randomization (ASLR) for extra fun. – datenwolf Mar 27 '15 at 18:41
  • A cast to `void *` is definitely required when passing an `int *` through the unnamed arguments to `printf` to be printed by `%p`; no automatic conversion occurs, the behavior is undefined per the rules for `va_arg`. This is true **even if** `void *` and `int *` have exactly the same representation; the standard permits the machine-level calling convention to have different rules for each. – zwol Mar 27 '15 at 20:27
  • @JohnBollinger Technically, int * could be arbitrarily larger with padding bits, just with fewer valid values than void *. This is even more unlikely than the two types being different in the first place, though. This discussion raises some interesting (standards-based and otherwise) questions about pointers, which may be on-topic for the site. – Random832 Mar 27 '15 at 20:38
  • @Random832, good point. I too often forget about the possibility of padding bits. *All* of the preceding arguments about the size of representations, by everyone participating, assume the same number of padding bits in the representations of all pointer types involved. If that assumption does not hold then you can't say *anything* about the relative sizes of the representations of different pointer types. – John Bollinger Mar 27 '15 at 21:17
  • @squeamishossifrage : I wanted to know why the addresses shown by the compilers differs in the syntax. The address given by C was smaller while that of C++ was long. I was not expecting both of them to give the same address tough the variable 'a' was global. – Developer101 Mar 28 '15 at 15:42

4 Answers4

17

Unless you are using some special, system-specific linker file, there are no guarantees of which address your variables will end up at in memory. It might even end up in different places from compilation to compilation on the same compiler. And of course different compilers will behave differently. There's no standard stating how they should allocate variables.

This has nothing to do with C versus C++. Both standards state that your variable should be allocated with static storage duration. All static storage duration variables that are not explicitly initialized are guaranteed by the C and C++ standards to get initialized to zero (see for example C11 6.7.9/10).

This means that both standards indirectly guarantee that the variable is allocated in .bss. Exactly where in the .bss is not specified anywhere.

Related question.

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396
5

This comparison makes no sense because C and C++ are different languages. Also you may get different output on each run of your code for same language on same machine using same compiler. It is not necessary that memory for variable a will be allocated at same location. The result is implementation defined.

C11: 7.21.6 (p8):

p The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.

Community
  • 1
  • 1
haccks
  • 104,019
  • 25
  • 176
  • 264
  • 1
    well, i do agree that the question is at least questionable, but I do not agree that the comparison makes no sense. The way variables are adressed in C and C++ can be compared and because they are different languages, there are differences that one can find. – 463035818_is_not_an_ai Mar 27 '15 at 15:12
  • 1
    Yes and I think it is not quite well formulated, because addresses differ from run to run (but not because C and C++ are different languages) – 463035818_is_not_an_ai Mar 27 '15 at 15:14
  • @tobi303; It depends on language too. Just compile the same code in C and C++ and see the effect. – haccks Mar 27 '15 at 15:16
  • 2
    ...so you agree, it makes sense to compare and there is a comparable effect. – 463035818_is_not_an_ai Mar 27 '15 at 15:17
  • @tobi303; Why you want to compare? – haccks Mar 27 '15 at 15:17
  • 1
    @tobi303, you are missing the point. The comparison does not make sense because nothing requires the output of the two programs to represent the same thing. For example, the implementation-defined manner in which Turbo C's `printf()` converts arguments corresponding to `%p` could be "convert the argument to the six-character sequence '0x00AA'". In actuality, the C version is probably printing an address offset, rather than an absolute address. – John Bollinger Mar 27 '15 at 16:06
2

Trying to answer in the spirit of the question - If you change your C++ program to be like this they will be the same.

int a;

int main (void) {

printf ("%p\n", &a);
cout << &a << endl;

return 0;
}

The address will be the same which is after all, is all that matters!

The C++ code will pull in more libraries and start up code and C++ default static data (cout,cerr,cin,etc..) than the C code. So the address may get pushed higher into memory. Also the starting address of the application maybe set differently for C and C++ or indeed random. In Visual C++ preferences you can have a "Randomised Base Address" or a "Fixed Base Address" Setting these will move the int a address.

AnthonyLambert
  • 8,768
  • 4
  • 37
  • 72
  • 1
    Most of what you say is right, but nothing *requires* a program built from your code to output two identical lines. The `%p` format doesn't have to output an absolute address, and I'm uncertain whether cout.<<(void *) is required to do so, either. Anyway, I suspect you are mis-diagnosing the problem. It is unlikely that the C version stores variable `a` at an absolute address as low as `0xAA`, or that the C++ version stores it at an offset of `0x8f970aa` bytes from any other reference point in the program, so I think the two are just doing different things. – John Bollinger Mar 27 '15 at 15:40
  • 1
    duh! yes no program requires both. I'm just showing the whole thing is irrelevant. – AnthonyLambert Mar 27 '15 at 15:47
0

The problem is not in the statements but rather both statements should have been in the same program. Because in different programs both have different addrress. In same program both would print the same address. I know one is C statment while the other in C++. But you can use both in same program.

Yasir Majeed
  • 739
  • 3
  • 12
  • 2
    No, there is absolutely no reason to suppose that the two statements would print identical lines if they appeared in the same program. They appear to be doing *different things*, and nothing requires otherwise. In particular, the C version is highly unlikely to be printing an absolute address, so it is probably printing a relative one, whereas the C++ version is highly unlikely to be printing a relative address, so it is probably printing an absolute one. – John Bollinger Mar 27 '15 at 15:59