Статическая инициализация массива структур в C

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

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

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

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

#define numBoxes 5

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

пробовал:

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

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

есть ли способ инициализировать все элементы этого массива структур без цикла?

Ура, - Джош!--4-->

5 ответов


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

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

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


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

если вы используете достаточно свежую версию 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;
    }
}

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


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


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

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

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

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

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

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

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