是否允许在其定义的右侧获取对象的地址,如下面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);
}
如果允许,是否对其使用有任何限制,例如,打印好了,我可以将它与另一个指针等进行比较吗?
在实践中,它似乎在我测试的编译器上进行编译,大部分时间都是预期的行为(但是not always),但这远非保证。
答案 0 :(得分:8)
要回答标题中的问题,请记住您的代码示例,是的。 C标准在§6.2.4中说得很多:
对象的生命周期是程序执行期间的一部分 保证保留哪个存储空间。存在一个对象, 具有恒定的地址,并始终保留其最后存储的值 它的一生。
对于没有可变长度数组类型的对象, 它的生命周期从进入到它所在的区块延伸 关联,直到该块的执行以任何方式结束。
所以是的,你可以从声明的角度获取变量的地址,因为对象在这一点上有地址并且在范围内。一个简明的例子如下:
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] },
};
答案 1 :(得分:7)
6.2.1标识符范围
- 结构,联合和枚举标记的范围在外观之后开始 声明标记的类型说明符中的标记。每个枚举常量都具有该范围 在枚举器列表中出现其定义的枚举器之后开始。的不限 其他标识符的范围在其声明者完成之后开始。
醇>
在
chars b = make(&b);
// ^^
声明符为b
,因此它在自己的初始化程序中。
6.2.4对象的存储持续时间
- 对于没有可变长度数组类型的[自动]对象,其生命周期延长 从进入与之关联的块直到该块的执行结束 无论如何。
醇>
所以在
{ // X
chars b = make(&b);
}
b
的生命周期从X
开始,因此在初始化程序执行时,它既活着又在范围内。
据我所知,这实际上与
完全相同{
chars b;
b = make(&b);
}
没有理由你不能在那里使用&b
。
答案 2 :(得分:0)
问题已经得到解答,但作为参考,它没有多大意义。这就是你编写代码的方法:
typedef struct { char x[100]; } chars;
chars make (void) {
chars c;
/* init c */
return c;
}
void foo(void) {
chars b = make();
}
或者最好在ADT或类似情况下,返回指向malloc
:ed对象的指针。按值传递结构通常不是一个好主意。