Статическая инициализация массива структур в 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
).