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

是否允许在其定义的右侧获取对象的地址,如下面的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); } 

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

在实践中,它似乎在我测试的编译器上进行编译,大部分时间都是预期的行为(但并非总是如此 ),但这远非保证。

6.2.1标识符的范围

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

 chars b = make(&b); // ^^ 

声明符是b ,因此它在自己的初始值设定项中。

6.2.4对象的存储持续时间

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

所以

 { // X chars b = make(&b); } 

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

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

 { chars b; b = make(&b); } 

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

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

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

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

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

 void *p = &p; 

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

至于你的第二个问题,你能用它做什么。 我可以说,在初始化完成之前,我不会使用该地址来访问该对象,因为初始化程序中表达式的求值评估顺序是不确定的(第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] }, }; 

问题已经得到解答,但作为参考,它没有多大意义。 这是你编写代码的方法:

 typedef struct { char x[100]; } chars; chars make (void) { chars c; /* init c */ return c; } void foo(void) { chars b = make(); } 

或者最好在ADT或类似情况下,返回指向malloc :ed对象的指针。 按值传递结构通常不是一个好主意。