[英]Assign member address to other member in struct
Is the following safe in C? C中的以下是安全的吗?
struct Buffer {
size_t size;
int8_t *storage;
};
struct Context {
struct Buffer buffer;
int8_t my_storage[10];
};
struct Context my_context = {
.buffer = {
.size = 0,
.storage = my_context.my_storage,
},
.my_storage = {0},
};
I am working with a micro controller and I don't want to have to use malloc. 我正在使用微控制器,我不想使用malloc。 Also, to me it looks better to collect everything in the struct rather than have the storage as a separate variable outside the Context.
另外,对我而言,收集结构中的所有内容而不是将存储作为Context之外的单独变量看起来更好。
[edit1] I have tested it and it compiles and works, as in the pointers to my_context.my_storage
and my_context.buffer.storage
are the same, with gcc (Debian 4.7.2-5) 4.7.2
on Linux ... 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u2 x86_64 GNU/Linux
[edit1]我已经测试了它并且它编译和工作,就像指向
my_context.my_storage
和my_context.buffer.storage
的指针一样,在Linux ... 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u2 x86_64 GNU/Linux
上使用gcc (Debian 4.7.2-5) 4.7.2
Linux ... 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u2 x86_64 GNU/Linux
[edit2] In an answer that was later deleted I was referred to C99 standard section 6.7.8-19 "The initialization shall occur in initializer list order..." Would that mean that [edit2]在后来删除的答案中,我被引用到C99标准第6.7.8-19节“初始化应在初始化程序列表顺序中发生......”这是否意味着
struct Context my_context = {
.my_storage = {0},
.buffer = {
.size = 0,
.storage = my_context.my_storage,
},
};
Is guaranteed to be safe? 保证安全吗? I interpret it that way.
我这样解释。
[edit3] Below is a full working example. [edit3]以下是一个完整的工作示例。
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
struct Buffer {
size_t size;
int8_t *storage;
};
struct Context {
struct Buffer buffer;
int8_t my_storage[10];
};
struct Context my_context = {
.buffer = {
.size = 0,
.storage = my_context.my_storage,
},
.my_storage = {0},
};
int
main(void)
{
printf ("ptr points to: %" PRIXPTR "\n", (uintptr_t)my_context.buffer.storage);
printf ("storage is at: %" PRIXPTR "\n", (uintptr_t)my_context.my_storage);
}
>> ./test
ptr points to: 600950
storage is at: 600950
Yes, this is fine. 是的,这很好。 Assuming
my_context
has automatic storage duration, its lifetime begins on entry to the associated block, and during its lifetime it has a constant address ( 6.2.4 Storage durations of objects /2). 假设
my_context
具有自动存储持续时间,其生命周期从进入相关块开始,并且在其生命周期内具有恒定地址( 6.2.4对象的存储持续时间 / 2)。 (If it has static or thread storage duration instead, then its lifetime extends for the duration of the entire program or thread respectively). (如果它具有静态或线程存储持续时间,则其生命周期分别延长整个程序或线程的持续时间)。
It follows that my_context.my_storage
also has a constant address over the lifetime of my_context
, so taking its address (via array-to-pointer decay) for the initialization of my_context.buffer.storage
will give the same value as it would after the initialization of my_context
is complete. 因此
my_context.my_storage
在my_context
的生命周期内也有一个常量地址,因此将其地址(通过数组到指针衰减)用于初始化my_context.buffer.storage
将得到与初始化后相同的值。 my_context
已完成。
Also note that the scope of my_context
begins at the point its declaration is complete, which is just prior to the =
of the initializer, so referring to it within its initializer is also fine. 还要注意
my_context
的范围从其声明完成的点开始,它刚好在初始化器的=
之前,所以在它的初始化器中引用它也没关系。
This doesn't really have anything to do with designated initializers and the order of initialization. 这与指定的初始化程序和初始化顺序没有任何关系。 What you are actually asking is if something like this is well-defined:
您实际要问的是,这样的事情是否定义明确:
typedef struct
{
int* ptr;
int val;
} struct_t;
struct_t s = {&s.val, 0};
And yes, I don't see why it shouldn't be. 是的,我不明白为什么不应该这样。 The compiler has to allocate
s
at an address in memory before attempting to initialize it. 在尝试初始化之前,编译器必须在内存中的地址处分配
s
。 The order in which the struct members is allocated or initialized shouldn't matter. 分配或初始化结构成员的顺序无关紧要。
However , writing initialization lists where one value of a struct depends on another value of the same struct is not safe! 但是 ,编写初始化列表,其中struct的一个值依赖于同一结构的另一个值是不安全的! C11 6.7.9/23 says:
C11 6.7.9 / 23说:
The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.
初始化列表表达式的评估相对于彼此不确定地排序,因此未指定任何副作用发生的顺序。
Assignment of a value to a variable is a "side effect". 将值赋值给变量是“副作用”。 So code like this is unsafe:
所以这样的代码是不安全的:
typedef struct
{
int val1;
int val2;
} struct_t;
struct_t s = {0, s.val1};
Because the compiler may evaluate the two expressions of the initializer list like this: 因为编译器可能会像这样评估初始化列表的两个表达式:
So even though the initialization order is guaranteed, the order of evaluation of the initialization list is not. 因此,即使初始化顺序得到保证,初始化列表的评估顺序也不是。 Though of course the compiler may have decided to evaluate the 0 expression first and then everything would have worked fine.
虽然编译器当然可能已经决定首先评估0表达式,然后一切都会正常工作。
The bottom line is, don't write obscure initialization lists. 底线是,不要写出模糊的初始化列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.