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

时间:2012-02-13 23:50:53

标签: c++ c struct

我可以在初始化struct Foo时执行此操作:

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

但是,我不能这样做:

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

所以,有两个问题:

  1. 为什么我不能做后者,前者只是初始化的特殊构造函数?
  2. 我怎样才能做类似于第二个例子的事情,即在已经初始化后的单行代码中为结构声明一堆变量?我试图避免对具有许多变量的大型结构执行此操作:

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

6 个答案:

答案 0 :(得分:29)

试试这个:

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

如果您有一个好的编译器(例如GCC),这将有效。您可能需要使用--std=gnu99打开C99模式,我不确定。

答案 1 :(得分:14)

第一个是聚合初始化程序 - 您可以在此解决方案中阅读这些和标记的初始化程序:

What is tagged structure initialization syntax?

这是一种特殊的初始化语法,在结构初始化后你不能做类似的事情。您可以做的是提供一个成员(或非成员)函数来将您的一系列值作为参数然后在成员函数中分配 - 这将允许您在以同样的方式初始化结构之后完成此操作简洁(当你第一次写完这个功能之后!)

答案 2 :(得分:9)

在C ++ 11中,您可以使用“tie”(在元组头中声明)

执行多个赋值
struct foo {
    int a, b, c;
} f;

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

如果您的右手表达式具有固定大小而您只需要获取某些元素,则可以使用带有tie的ignore占位符

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

如果您发现语法std :: tie(f.a,f.b,f.c)代码混乱,您可以使用成员函数返回引用元组

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);

所有这一切都假设重载赋值运算符不是一个选项,因为你的结构不能通过这样的值序列构造,在这种情况下你可以说

f = foo(1, 2, 3);

答案 3 :(得分:3)

如果您不太关心效率,可以双重分配:即使用聚合初始化创建结构的新实例,然后将其复制:

struct Foo foo;

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

确保将部分包裹在{}中,以便在不再需要时立即丢弃不必要的临时变量。

注意,这不如在结构(如果是c ++)或结构中使用'set'函数,接受结构指针(如果是C)那样有效。但是如果你需要一个快速的,最好是临时的替代方法来编写逐个元素的赋值,那么这可能就行了。

答案 4 :(得分:2)

记忆足迹 - 这是一个有趣的i386补充。

经过多次麻烦后,使用优化 memcpy 似乎使用带有GCC和C99的i386生成最小的占用空间。我在这里使用-O3。 stdlib似乎有各种有趣的编译器优化,这个例子使用了它(memcpy实际上是在这里编译的)。

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

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;
}

<强>结果:

  • (。rodata)FOO_ASSIGN_VAL存储在.rodata
  • (。text)* movl FOO_ASSIGN_VAL,%registers *出现的序列
  • (。text)一系列 movl%寄存器,foo 发生

示例:

  • Say Foo是uint8_t值的48字段结构。它在记忆中对齐。

  • IDEAL )在32位计算机上,此 COULD 与12条MOVL指令一样快,即可终止foo的地址空间。对我来说,这是12 * 10 == 120bytes的.text大小。

  • ACTUAL )但是,使用AUTO的答案可能会在.text中生成48条MOVB指令。对我来说,这是48 * 7 == 336bytes的.text !!

  • SMALLEST * )使用上面的memcpy版本。 IF对齐得到了解,

    • FOO_ASSIGN_VAL位于.rodata(48字节),
    • 12 MOVL into%register
    • 12个MOVL outof%寄存器用于.text(24 * 10)== 240bytes。
    • 对我来说,这总共是288个字节。

所以,对我来说至少使用我的i386代码,

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

*这里最小的意思是“我知道的最小足迹”。它的执行速度也比上述方法快(24条指令对48条)。当然,IDEAL版本是最快的&amp;最小的,但我仍然无法弄明白。

-Justin

*有谁知道如何在上面实施' IDEAL '?这让我很烦恼!

答案 5 :(得分:0)

如果你关心效率,你可以定义一个与你的结构长度相同的联合,你可以一次分配一个类型。

要按元素分配值,请使用union的结构,分配整个数据,使用其他类型的union。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;

namespace DataflowTest
{
    class Program
    {
        public const int BATCH_SIZE = 10;
        static void Main(string[] args)
        {
            Console.WriteLine("Application started");

            //Create the pipeline of actions
            var transformBlock = new TransformBlock<string, string>(input => TransformString(input), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 });
            var batchBlock = new BatchBlock<string>(BATCH_SIZE);
            var uploadFilesToAzureBlock = new ActionBlock<IEnumerable<string>>(strings => OutputStrings(strings), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 });

            Console.WriteLine("Blocks created");

            //link the actions
            transformBlock.LinkTo(batchBlock);
            batchBlock.LinkTo(uploadFilesToAzureBlock);
            batchBlock.Completion.ContinueWith(obj => uploadFilesToAzureBlock.Complete());

            Console.WriteLine("Blocks linked");

            var testInputs = new List<string>
            {
                "Kyle",
                "Stephen",
                "Jon",
                "Conor",
                "Adrian",
                "Marty",
                "Richard",
                "Norbert",
                "Kerri",
                "Mark",
                "Declan",
                "Ray",
                "Paul",
                "Andrew",
                "Rachel",
                "David",
                "Darrell"
            };

            Console.WriteLine("Data created");

            var i = 0;
            foreach (var name in testInputs)
            {
                Console.WriteLine("Posting name {0}", i);
                transformBlock.Post(name);
                i++;
            }

            batchBlock.Complete();
            uploadFilesToAzureBlock.Completion.Wait();

            Console.WriteLine("Finishing");
            Console.ReadKey();
        }

        private static void OutputStrings(IEnumerable<string> strings)
        {
            Console.WriteLine("Beginning Batch...");

            foreach (var s in strings)
            {
                Console.WriteLine(s);
            }

            Console.WriteLine("Completing Batch...");
        }

        private static string TransformString(string input)
        {
            return input += " has been processed";
        }
    }
}

小心你的记忆组织(是“一个”MSB还是“整体”的LSB?)。