可以在其定义中采用具有自动存储持续时间的变量的地址吗?

Bee*_*ope 3 c language-lawyer c11

是否允许在其定义的右侧获取对象的地址,foo()如下所示:

typedef struct { char x[100]; } chars;

chars make(void *p) {
  printf("p = %p\n", p);
  chars c;
  return c;
}

void foo(void) {
  chars b = make(&b);
}
Run Code Online (Sandbox Code Playgroud)

如果允许,它的使用是否有任何限制,例如,打印好了,我可以将它与另一个指针等进行比较吗?

在实践中,它似乎在我测试的编译器上编译,在大多数时间(但并非总是)具有预期的行为,但这远非保证.

Sto*_*ica 8

要回答标题中的问题,请记住您的代码示例,是的.C标准在§6.2.4说得很多:

对象的生命周期是程序执行的一部分,在此期间保证为其保留存储.存在一个对象,具有一个常量地址,并在其整个生命周期内保留其最后存储的值.

对于没有可变长度数组类型的此类对象,其生命周期从entry进入与其关联的块,直到该块的执行以任何方式结束.

所以,是的,您可以从声明的角度获取变量的地址,因为该对象在此时具有地址并且它在范围内.这是一个浓缩的例子如下:

void *p = &p;
Run Code Online (Sandbox Code Playgroud)

它的用途很少,但完全有效.

至于你的第二个问题,你能用它做什么.我可以说,在初始化完成之前,我不会使用该地址来访问该对象,因为初始化程序中表达式的评估顺序是不可靠的(第6.7.9节).你可以很容易地找到你的脚.

实现这一目标的一个地方是定义需要自引用的各种表格数据结构.例如:

typedef struct tab_row {
  // Useful data
  struct tab_row *p_next;
} row;

row table[3] = {
  [1] = { /*Data 1*/, &table[0] },
  [2] = { /*Data 2*/, &table[1] },
  [0] = { /*Data 0*/, &table[2] },
};
Run Code Online (Sandbox Code Playgroud)

  • @BeeOnRope取决于您使用的运算符.`==`或`!=`很好.`<`和朋友需要指向同一个数组的操作数. (2认同)

mel*_*ene 7

6.2.1标识符的范围

  1. 结构,联合和枚举标记具有在声明标记的类型说明符中标记出现之后开始的范围.每个枚举常量都具有在枚举器列表中定义枚举器出现之后开始的范围.任何其他标识符的范围都在其声明者完成之后开始.

chars b = make(&b);
//    ^^
Run Code Online (Sandbox Code Playgroud)

声明者是b,因此它在自己的初始化程序中.

6.2.4对象的存储持续时间

  1. 对于没有可变长度数组类型的这种[自动]对象,其生命周期从入口延伸到与其关联的块,直到该块的执行以任何方式结束.

所以

{ // X
  chars b = make(&b);
}
Run Code Online (Sandbox Code Playgroud)

b开始的生命周期X,因此在初始化程序执行时,它既活着又在范围内.

据我所知,这实际上是相同的

{
  chars b;
  b = make(&b);
}
Run Code Online (Sandbox Code Playgroud)

没有理由你不能&b在那里使用.