Статическая инициализация массива структур в C - PullRequest
7 голосов
/ 21 ноября 2011

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

По сути, я имеюглобальный массив структур типа "memPermissions", показанный ниже.В этом массиве все поля "address" и "ownerId" должны быть инициализированы значением -1 при выполнении программы.

typedef struct memPermissions {
    int address;
    int ownerId;
} *test;

Проблема в том, что размер массива определяется с помощью #define, поэтому я просто не могу перейти:

#define numBoxes 5

struct memPermissions memPermissions[numBoxes] = {
{-1, -1},
...
{-1, -1}
};

Я пытался:

struct memPermissions memPermissions[numBoxes] = {-1, -1};

Но, естественно, это только инициализировал первый элемент.(Остальные были установлены на 0).Единственное решение, которое приходит мне на ум, - это где-то инициализировать его простым циклом, но из-за характера того, где этот код будет выполняться, я действительно надеюсь, что это не единственный вариант.

Есть ли какой-нибудьспособ инициализации всех элементов этого массива структур без цикла?

Cheers, -Josh

Ответы [ 5 ]

8 голосов
/ 21 ноября 2011

Стандарт C99 добавил всевозможные полезные способы инициализации структур, но не предоставил оператор повтора (который у Фортрана был с тех пор навсегда - но, возможно, это было , почему не было добавлено).

Если вы используете достаточно свежую версию GCC и можете позволить себе использовать непереносимое расширение, то GCC предоставляет расширение.В руководстве GCC 8.1.0 ( §6.27 Назначенные инициализаторы ) говорится:

Чтобы инициализировать диапазон элементов одним и тем же значением, напишите '[first ...последний] = значение '.Это расширение GNU.Например,

int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

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

Итак, используя это в вашем примере:

struct memPermissions memPermissions[numBoxes] =
{
    [0..numBoxes-1] = {-1, -1},    // GCC extension
};

Я бы хотел, чтобы это было в Стандарте C;это было бы очень полезно!


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

#include <string.h>
#include "memperm.h"  // Header declaring your types and variables

static int initialized = 0;
// -2 so the initialization isn't uniform and memset() is not an option
static const struct memPermissions initPermissions = { -1, -2 };
struct memPermissions memPermissions[numBoxes];

void initialize_permissions(void)
{
    if (initialized == 0)
    {
        for (int i = 0; i < numBoxes; i++)
            memmove(&memPermissions[i], &initPermissions, sizeof(initPermissions));
        initialized = 1;
    }
}

Вы также можете использовать memcpy() здесь - нет опасности перекрытия двух переменных.

Теперь вам просто нужно убедиться, что initialize_permissions() вызывается перед использованием массива - желательно только один раз.Для этого тоже могут существовать механизмы, специфичные для компилятора.

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

Если у вас есть компилятор C99, вы можете использовать составной литерал вместо константы:

void initialize_permissions(void)
{
    if (initialized == 0)
    {
        for (int i = 0; i < numBoxes; i++)
            memmove(&memPermissions[i],&(struct memPermissions){ -1, -2 },
                    sizeof(memPermissions[0]));
        initialized = 1;
    }
}
2 голосов
/ 21 ноября 2011

Вы можете написать внешнюю программу, которой передано количество элементов, которое вы хотите.Эта программа должна вызываться вашим Makefile или его эквивалентом.Программа напишет для вас включаемый файл с необходимым количеством значений -1, а также #define.

1 голос
/ 21 ноября 2011

Если у вас есть стандартная библиотека, вы можете использовать memset в сочетании с sizeof(struct memPermissions) * numBoxes, чтобы заполнить ваш массив любым унифицированным байтовым значением. Поскольку -1 на многих платформах 0xFFFFFFFF, это может сработать для вас.

0 голосов
/ 21 ноября 2011

Если действительно важно не использовать цикл, вы можете сделать что-то довольно странное и использовать / злоупотреблять memset, предполагая, что это доступно.

NB Memset может быть реализован с использованием цикла, поэтому он может быть спорным.

memset(memPermissions, 0xFF, sizeof(memPermissions)*numBoxes*2*sizeof(int));

Время 2 необходимо для обоих членов структуры (т.е. дваиз них).

Это плохо спроектировано, поскольку зависит от того, что структура не дополнена и не выровнена, что компилятор может сделать так в соответствии со спецификациями Си.

(Использование этого-1 обычно 0xFFFFFFFF для отрицательных целых чисел с 2 комплиментами на 32-разрядных процессорах, с 32-разрядными int. Слава @James за указание на это.)

Хотя я подозреваю, что в большинствеслучаи, когда код будет реализован в виде небольшого, быстрого, трудного цикла (rep movsd для x86) на языке ассемблера во всех случаях, кроме самого тривиального (очень маленькие значения numBoxes).

0 голосов
/ 21 ноября 2011

Единственное решение, которое приходит мне на ум - инициализировать его простым циклом где-то

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

Однако вы можете обойти проблему, используя 0 для целей, которые в данный момент обслуживает ваш -1.

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