简体   繁体   English

如何一次将多个值分配给一个结构?

[英]how to assign multiple values into a struct at once?

I can do this on initialization for a struct Foo:我可以在初始化 struct Foo 时执行此操作:

Foo foo =  {bunch, of, things, initialized};

but, I can't do this:但是,我不能这样做:

Foo foo;
foo = {bunch, of, things, initialized};

So, two questions:所以,两个问题:

  1. Why can't I do the latter, is the former a special constructor for initialization only?为什么我不能做后者,前者只是初始化的特殊构造函数吗?
  2. How can I do something similar to the second example, ie declare a bunch of variables for a struct in a single line of code after it's already been initialized?我怎样才能做类似于第二个例子的事情,即在它已经被初始化之后,在一行代码中为一个结构声明一堆变量? I'm trying to avoid having to do this for large structs with many variables:我试图避免对具有许多变量的大型结构执行此操作:

     Foo foo; foo.a = 1; foo.b = 2; foo.c = 3; //... ad infinitum

Try this:尝试这个:

Foo foo;
foo = (Foo){bunch, of, things, initialized};

This will work if you have a good compiler (eg GCC).如果您有一个好的编译器(例如 GCC),这将起作用。 You might need to turn on C99 mode with --std=gnu99 , I'm not sure.您可能需要使用--std=gnu99打开 C99 模式,我不确定。

Update: In modern versions of C (but not C++), you can also use a compound literal with designated initializers, which looks like this:更新:在现代版本的 C(但不是 C++)中,您还可以使用带有指定初始值设定项的复合文字,如下所示:

foo = (Foo){ .bunch = 4, .of = 2, .things = 77, .initialized = 8 };

The name right after the "." “。”之后的名称。 should be the name of the structure member you wish to initialize.应该是您希望初始化的结构成员的名称。 These initializers can appear in any order, and any member that is not specified explicitly will get initialized to zero.这些初始化器可以以任何顺序出现,并且任何未明确指定的成员都将被初始化为零。

The first is an aggregate initializer - you can read up on those and tagged initializers at this solution:第一个是聚合初始值设定项 - 您可以在此解决方案中阅读这些和标记的初始值设定项:

What is tagged structure initialization syntax? 什么是标记结构初始化语法?

It is a special initialization syntax, and you can't do something similar after initialization of your struct.这是一种特殊的初始化语法,在初始化结构后你不能做类似的事情。 What you can do is provide a member (or non-member) function to take your series of values as parameters which you then assign within the member function - that would allow you to accomplish this after the structure is initialized in a way that is equally concise (after you've written the function the first time of course!)您可以做的是提供一个成员(或非成员)函数,将您的一系列值作为参数,然后在成员函数中分配 - 这将允许您在以同样的方式初始化结构后完成此操作简洁(当然是在你第一次编写函数之后!)

In C++11 you can perform multiple assignment with "tie" (declared in the tuple header)在 C++11 中,您可以使用“tie”(在元组标头中声明)执行多重赋值

struct foo {
    int a, b, c;
} f;

std::tie(f.a, f.b, f.c) = std::make_tuple(1, 2, 3);

If your right hand expression is of fixed size and you only need to get some of the elements, you can use the ignore placeholder with tie如果你的右手表达式是固定大小的,你只需要获取一些元素,你可以使用带有 tie 的忽略占位符

std::tie(std::ignore, f.b, std::ignore) = some_tuple; // only f.b modified

If you find the syntax std::tie(fa, fb, fc) too code cluttering you could have a member function returning that tuple of references如果你发现语法 std::tie(fa, fb, fc) 太乱,你可以有一个返回引用元组的成员函数

struct foo {
    int a, b, c;
    auto members() -> decltype(std::tie(a, b, c)) {
        return std::tie(a, b, c);
    }
} f;

f.members() = std::make_tuple(1, 2, 3);

All this ofcourse assuming that overloading the assignment operator is not an option because your struct is not constructible by such sequence of values, in which case you could say所有这些当然都假设重载赋值运算符不是一种选择,因为你的结构不能由这样的值序列构造,在这种情况下你可以说

f = foo(1, 2, 3);

Memory Footprint - Here is an interesting i386 addition. Memory Footprint - 这是一个有趣的 i386 添加。

After much hassle, using optimization and memcpy seems to generate the smallest footprint using i386 with GCC and C99.经过很多麻烦,使用优化memcpy似乎使用 i386 与 GCC 和 C99 生成最小的占用空间。 I am using -O3 here.我在这里使用 -O3 。 stdlib seems to have all sorts of fun compiler optimizations at hand, and this example makes use of that (memcpy is actually compiled out here). stdlib 似乎手头有各种有趣的编译器优化,这个例子利用了它(memcpy 实际上是在这里编译出来的)。

Do this by:通过以下方式执行此操作:

Foo foo; //some global variable

void setStructVal (void)   {

    const Foo FOO_ASSIGN_VAL = {    //this goes into .rodata
            .bunch       = 1,
            .of          = 2,
            .things      = 3,
            .initialized = 4
    };

    memcpy((void*) &FOO_ASSIGN_VAL, (void*) foo, sizeof(Foo));

    return;
}

Result:结果:

  • (.rodata) FOO_ASSIGN_VAL is stored in .rodata (.rodata) FOO_ASSIGN_VAL 存储在 .rodata
  • (.text) a sequence of *movl FOO_ASSIGN_VAL, %registers* occur (.text) 一系列 *movl FOO_ASSIGN_VAL, %registers* 发生
  • (.text) a sequence of movl %registers, foo occur (.text) 一系列movl %registers, foo发生

Example:例子:

  • Say Foo was a 48 field struct of uint8_t values.说 Foo 是一个 48 个字段的 uint8_t 值结构。 It is aligned in memory.它在内存中对齐。

  • ( IDEAL ) On a 32-bit machine, this COULD be as quick as 12 MOVL instructions of immediates out to foo's address space. 理想)在 32 位机器上,这可以像 12 条立即输出到 foo 的地址空间的MOVL指令一样快。 For me this is 12*10 == 120bytes of .text in size.对我来说,这是 12*10 == 120 字节的 .text 大小。

  • ( ACTUAL ) However, using the answer by AUTO will likely generate 48 MOVB instructions in .text. 实际)但是,使用 AUTO 的答案可能会在 .text 中生成 48 条 MOVB 指令。 For me this is 48*7 == 336bytes of .text!!对我来说,这是 48*7 == 336 字节的 .text!

  • ( SMALLEST* ) Use the memcpy version above. ( SMALLEST* ) 使用上面的 memcpy 版本。 IF alignment is taken care of, IF对齐得到照顾,

    • FOO_ASSIGN_VAL is placed in .rodata (48 bytes), FOO_ASSIGN_VAL 放在 .rodata 中(48 字节),
    • 12 MOVL into %register 12 MOVL 进入 % 寄存器
    • 12 MOVL outof %registers are used in .text (24*10) == 240bytes. .text (24*10) == 240bytes 中使用了 12 个 MOVL outof %registers。
    • For me then this is a total of 288 bytes.对我来说,这总共是 288 个字节。

So, for me at least with my i386 code,所以,至少对我来说,我的 i386 代码,

- Ideal:    120 bytes
- Direct:   336 bytes
- Smallest: 288 bytes

*Smallest here means 'smallest footprint I know of'. *这里最小的意思是“我所知道的最小的足迹”。 It also executes faster than the above methods (24 instructions vs 48).它的执行速度也比上述方法更快(24 条指令对 48 条)。 Of course, the IDEAL version is fastest & smallest, but I still can't figure that out.当然,IDEAL 版本是最快和最小的,但我还是想不通。

-Justin -贾斯汀

*Does anyone know how to get implementation of ' IDEAL ' above? *有人知道如何实现上面的' IDEAL '吗? It is annoying the hell out of me!!真是烦死我了!!

If you don't care too much about efficiency, you could double assign: ie create a new instance of the structure using aggregate initialization, and then copy it over:如果您不太关心效率,您可以双重分配:即使用聚合初始化创建结构的新实例,然后将其复制过来:

struct Foo foo;

{
  struct Foo __tmp__ = {bunch, of, things, initialized};
  foo = __tmp__;
}

Make sure you keep the portion wrapped in {}s so as to discard the unnecessary temporary variable as soon as it's no longer necessary.确保将部分包裹在 {} 中,以便在不再需要时立即丢弃不必要的临时变量。

Note this isn't as efficient as making, eg, a 'set' function in the struct (if c++) or out of the struct, accepting a struct pointer (if C).请注意,这不如在结构中(如果是 c++)或在结构外创建一个“set”函数,接受一个结构指针(如果是 C)那么有效。 But if you need a quick, preferably temporary, alternative to writing element-by-element assignment, this might do.但是,如果您需要一个快速的、最好是临时的替代方法来编写逐个元素的赋值,这可能会做到。

If you care about efficiency, you can define a union of the same length as your structure, with a type you can assign at once.如果您关心效率,您可以定义一个与您的结构长度相同的联合,并且您可以立即分配一个类型。

To assign values by elements use the struct of your union, to assign the whole data, use the other type of your union.要按元素分配值,请使用联合的结构,要分配整个数据,请使用联合的其他类型。

typedef union
{
    struct
    {
      char a;
      char b;
    } Foo;
    unsigned int whole;
} MyUnion;

MyUnion _Union;
_Union.Foo.a = 0x23;    // assign by element
_Union.Foo.b = 0x45;    // assign by element
_Union.whole = 0x6789;  // assign at once

Be carefull about your memory organization (is "a" the MSB or the LSB of "whole"?).小心你的记忆组织(“a”是“whole”的 MSB 还是 LSB?)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM