是否可以在其定义中取自动存储期限的变量的地址?
Can the address of a variable with automatic storage duration be taken in its definition?
是否允许在其定义的右侧获取对象的地址,如下面的 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 Scopes of identifiers
- 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.
在
chars b = make(&b);
// ^^
声明符是 b
,因此它在其自己的初始化程序的范围内。
6.2.4 Storage durations of objects
- For such an [automatic] object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way.
所以在
{ // X
chars b = make(&b);
}
b
的生命周期从 X
开始,因此在初始化程序执行时,它既是活动的又在范围内。
据我所知,这实际上与
相同
{
chars b;
b = make(&b);
}
没有理由你不能在那里使用 &b
。
要回答标题中的问题,请记住您的代码示例,是的。 C 标准在 §6.2.4:
中说了这么多
The lifetime of an object is the portion of program execution during
which storage is guaranteed to be reserved for it. An object exists,
has a constant address, and retains its last-stored value throughout
its lifetime.
For such an object that does not have a variable length array type,
its lifetime extends from entry into the block with which it is
associated until execution of that block ends in any way.
所以是的,您可以从声明点获取变量的地址,因为 object 具有此时的地址并且它在范围内。下面是一个浓缩示例:
void *p = &p;
它的作用很小,但完全有效。
关于你的第二个问题,你能用它做什么。我主要可以说在初始化完成之前我不会使用该地址访问 object,因为初始化器中表达式的求值顺序未指定 (§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 或类似的情况下,return 指向 malloc
:ed 对象的指针可能更好。按值传递结构通常不是一个好主意。
是否允许在其定义的右侧获取对象的地址,如下面的 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 Scopes of identifiers
- 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.
在
chars b = make(&b);
// ^^
声明符是 b
,因此它在其自己的初始化程序的范围内。
6.2.4 Storage durations of objects
- For such an [automatic] object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.
所以在
{ // X
chars b = make(&b);
}
b
的生命周期从 X
开始,因此在初始化程序执行时,它既是活动的又在范围内。
据我所知,这实际上与
相同{
chars b;
b = make(&b);
}
没有理由你不能在那里使用 &b
。
要回答标题中的问题,请记住您的代码示例,是的。 C 标准在 §6.2.4:
中说了这么多The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime.
For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.
所以是的,您可以从声明点获取变量的地址,因为 object 具有此时的地址并且它在范围内。下面是一个浓缩示例:
void *p = &p;
它的作用很小,但完全有效。
关于你的第二个问题,你能用它做什么。我主要可以说在初始化完成之前我不会使用该地址访问 object,因为初始化器中表达式的求值顺序未指定 (§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 或类似的情况下,return 指向 malloc
:ed 对象的指针可能更好。按值传递结构通常不是一个好主意。