как назначить несколько значений в структуру одновременно? - PullRequest
38 голосов
/ 14 февраля 2012

Я могу сделать это при инициализации для структуры 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 ]

30 голосов
/ 14 февраля 2012

Попробуйте:

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

Это будет работать, если у вас есть хороший компилятор (например, GCC).Возможно, вам придется включить режим C99 с помощью --std=gnu99, я не уверен.

14 голосов
/ 14 февраля 2012

Первый - агрегатный инициализатор - вы можете прочитать об этих и помеченных инициализаторах в этом решении:

Что такое синтаксис инициализации теговой структуры?

Это специальный синтаксис инициализации, и вы не можете сделать что-то подобное после инициализации вашей структуры. Что вы можете сделать, так это предоставить функцию-член (или не-член), которая будет принимать серию значений в качестве параметров, которые вы затем назначаете в функции-члене, что позволит вам сделать это после инициализации структуры таким же образом краткий (после того как вы написали эту функцию в первый раз, конечно!)

9 голосов
/ 02 февраля 2014

В 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

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

Если вы обнаружите, что синтаксис 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);

Все это, конечно, предполагая, что перегрузка оператора присваивания не является опцией, потому что ваша структура не может быть построена такой последовательностью значений, и в этом случае вы могли бы сказать

f = foo(1, 2, 3);
3 голосов
/ 25 марта 2013

Если вас не слишком заботит эффективность, вы можете дважды назначить: создать новый экземпляр структуры, используя агрегатную инициализацию, а затем скопировать его:

struct Foo foo;

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

Убедитесь, что вы храните часть, завернутую в {}, чтобы отбросить ненужную временную переменную, как только она больше не нужна.

Обратите внимание, что это не так эффективно, как сделать, например, функцию 'set' в структуре (если c ++) или вне структуры, принимая указатель структуры (если C). Но если вам нужна быстрая, желательно временная, альтернатива написанию поэлементного присваивания, это может подойти.

2 голосов
/ 07 января 2014

Memory Footprint - вот интересное дополнение i386.

После долгих хлопот использование оптимизация и memcpy , кажется, генерирует наименьшееиспользование i386 с GCC и C99.Я использую здесь -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,% регистров* происходят
  • (. текст) последовательность регистров movl%, foo встречаются

Пример:

  • Скажем, Фу был структурой из 48 полей значений uint8_t.Он выровнен в памяти.

  • ( IDEAL ) На 32-разрядной машине это МОЖЕТ быть быстрым, как 12 команд MOVLнемедленно выходит в адресное пространство foo.Для меня это 12 * 10 == 120 байт .text по размеру.

  • ( ACTUAL ) Однако использование ответа AUTO, скорее всего, сгенерирует 48 инструкций MOVBв тексте.Для меня это 48 * 7 == 336 байт .text !!

  • ( SMALLEST *) Используйте версию memcpy выше.Если выполняется выравнивание,

    • FOO_ASSIGN_VAL помещается в .rodata (48 байт),
    • 12 MOVL в регистр%
    • 12 MOVL из% регистровиспользуется в .text (24 * 10) == 240 байт.
    • Для меня это всего 288 байт.

Итак, по крайней мере для меня с моим кодом i386,

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

* Наименьшее здесь означает «наименьший след, который я знаю».Он также выполняется быстрее, чем описанные выше методы (24 инструкции против 48).Конечно, версия IDEAL самая быстрая и самая маленькая, но я все еще не могу понять это.

-Justin

* Кто-нибудь знает, как получить реализацию ' IDEAL 'выше?Это чертовски раздражает меня !!

0 голосов
/ 04 августа 2015

Если вы заботитесь об эффективности, вы можете определить объединение той же длины, что и ваша структура, с типом, который вы можете назначить сразу.

Чтобы присваивать значения элементам, используйте структуру вашего объединения, для назначения целых данных используйте другой тип вашего объединения.

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

Будьте осторожны с организацией вашей памяти (является "a" MSB или LSB "целого"?).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...