16

I wanted to see if I could initialize a global variable to point to itself:

#include <stdio.h>
struct foo { struct foo *a, *b; } x = { &x, &x };
int main()
{
    printf("&x = %p, x.a = %p, x.b = %p\n", &x, x.a, x.b);
    return 0;
}

This code compiles and runs as expected with gcc (all three pointers print identically).

I want to know:

  1. Is this reliable?
  2. Is this standard?
  3. Is this portable?

EDIT: Just to clarify, I am questioning the availability of the address of x in its own initializer.

Matt
  • 17,895
  • 16
  • 55
  • 102
  • There's one problem: `%p` expects a `void*`, but the arguments are `struct foo*`s. – Daniel Fischer May 29 '12 at 21:23
  • @DanielFischer Doesn't C allow silent conversions to and from `void *` from any other pointer in order to allow functions such as `malloc` to work without explicit conversions? – Matt May 29 '12 at 21:25
  • 1
    It does, but only on assignment. When passing stuff to `printf`, no such conversion happens (varargs, no type checking at all). So `printf` gets `struct foo*`s, but the format string requires `void*`. Your compiler should warn you about that (if you turn the warning level up). Pedantically, that's even undefined behaviour, though it'll work as intended on most common platforms (the standard doesn't guarantee that all pointers have the same size and structure, but usually they have). – Daniel Fischer May 29 '12 at 21:33
  • 1
    @DanielFischer That's interesting. I always thought that pointers are always guaranteed to be the same size (except for pointers to member functions in C++, but this is not C++). – Matt May 29 '12 at 21:38
  • No, they aren't, unfortunately, and on some oldish platforms, there were pointers of different sizes (some platforms had near and far pointers of different sizes, http://stackoverflow.com/a/399999/1011995 is what I quickly found). – Daniel Fischer May 29 '12 at 21:48
  • Also this: http://stackoverflow.com/a/3941817/1011995 – Daniel Fischer May 29 '12 at 22:04

2 Answers2

8

Yes to all of the above. You have a couple of pointers that you're initializing with the same address, so they hold the same address, and that's the same as the address with which you initialized them.

Perhaps more interestingly, x.a is also guaranteed to point to itself (i.e., the first element in a struct is guaranteed to be at the very beginning of the struct, so a pointer to the struct, converted to the type of the first element, is guaranteed to point to that first element.

Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035
  • What I was questioning was whether the address of `x` is available in the initializer clause. Also, you are right that `x.a` points to the same location as itself but the type is different `x.a` is a `struct foo *` and should point to a `struct foo` which is not the same type as itself. – Matt May 29 '12 at 20:51
  • @Matt: Yes, the address is an rvalue (essentially, a constant), so from the viewpoint of the program, this isn't much different from something like `int x = 1234;` – Jerry Coffin May 29 '12 at 20:58
8

This is standard C code.

This paragraph of the mighty Standard permits it (emphasis mine):

(C99, 6.2.1p7) "Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag. Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list. Any other identifier has scope that begins just after the completion of its declarator."

For information, note that to illustrate the last sentence of 6.2.1p7, the book "The New C Standard" by Derek M. Jones uses an example similar to yours:

struct T {struct T *m;} x = /* declarator complete here. */ {&x};
ouah
  • 134,166
  • 14
  • 247
  • 314