Заполнение массива C

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

int a[] = {1, 2, 3, 4};
int b[] = {1, 2, 3, 4, 5};

Для обеспечения согласованности строк кэша я хочу дополнить их до размера строки кэша (32). Следующий код можно использовать без уточнения точной информации о размере.

struct {
   int payload[4];
} __attribute__((aligned(32))) a = {
   .payload = {1, 2, 3, 4}
};

struct {
   int payload[5];
} __attribute__((aligned(32))) b = {
   .payload = {1, 2, 3, 4, 5}
};

// sizeof(a.payload) == 4 * sizeof(int), sizeof(b.payload) == 5 * sizeof(int)

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

#define ARRAY_INITIALIZER (array, initializer) ...
#define ARRAY_PAYLOAD(array) array.payload
ARRAY_INITIALIZER(a, {1, 2, 3, 4});
ARRAY_INITIALIZER(b, {1, 2, 3, 4, 5});

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

Это может быть полезно: stackoverflow.com/questions/2124339/… Да, это C++, но определение макроса может подойти и вам.

zerocukor287 06.08.2024 10:05

Можно ли применить __attribute__((aligned(32))) к массиву как одну переменную, а не как поле структуры?

Stas Simonov 06.08.2024 10:15

Зачем помещать массивы в структуру? Ваш реальный вопрос, как выровнять исходные 32-байтовые массивы?

nielsen 06.08.2024 12:56

@nielsen, размещение внутри структуры имеет 2 эффекта: 1) заполнение конечных данных, не только выравнивание по началу, но и выравнивание по концу 2) sizeof все равно можно получить фактический размер без конечного заполнения

Eric Sun 06.08.2024 13:01

@StasSimonov, aligned to переменная приведет к выравниванию только по началу, скажем, массив из 5 начинается с выравнивания по 32, левые 27 байтов все еще доступны для выделения другим переменным, мы хотим, чтобы он занимал полные 32 байта, чтобы избежать проблем с когерентностью кеша

Eric Sun 06.08.2024 13:02

@SupportUkraine, вы правы, я внесу изменения

Eric Sun 06.08.2024 14:07
__attribute__ — это GNU-изм. Некоторые другие реализации C поддерживают его для совместимости с GCC, но это не стандарт C.
John Bollinger 06.08.2024 16:28

Но GNU C позволяет применять __attribute__((aligned)) как к переменным, так и к типам, поэтому я не совсем понимаю, почему вы рассматриваете возможность обертывания массивов в структуры только для выравнивания.

John Bollinger 06.08.2024 16:33

@JohnBollinger, __attribute__((aligned)) к переменной выравнивает только ее начало. При применении его к структуре он выравнивает начало и конец. См. Ссылка1 и Ссылка2.

Eric Sun 07.08.2024 10:07
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
3
9
112
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Эта инициализация создает выровненные адреса либо на C, либо на C++:

#include <stdalign.h>

alignas(32) int a[] = {1, 2, 3, 4} ;
alignas(32) int b[] = {1, 2, 3, 4, 5};
sizeof(b) равно 20, что не выровнено по 32 байтам, что оставляет возможность того, что b и другие переменные находятся в одной строке кэша, что может вызвать потенциальные проблемы.
Eric Sun 07.08.2024 09:37
Ответ принят как подходящий

Вот одна из идей использования вариативных макросов:

#include <stdalign.h> // for "alignas" - not needed since C23

#define VA_COUNT(...) (sizeof((int[]){0, __VA_ARGS__}) / sizeof(int) - 1)

#define ARRAY_INITIALIZER(V, ...)                       \
    struct {                                            \
        alignas(32) int payload[VA_COUNT(__VA_ARGS__)]; \
    } V = {.payload = {__VA_ARGS__}}

Обратите внимание, что стандарт _Alignas (alignas) используется для выравнивания массива. Размер полезной нагрузки рассчитывается с помощью VA_COUNT.

Пример использования:

#include <stdio.h>

// the macro definitions from above goes here

#define SIZE(x) (sizeof(x) / sizeof *(x))

int main(void) {
    ARRAY_INITIALIZER(a, 1, 2, 3, 4);

    for (unsigned i = 0; i < SIZE(a.payload); ++i) {
        printf("%d\n", a.payload[i]);
    }
}

Выход:

1
2
3
4

Привет, Тед. В моей среде нет alignas, поэтому я все еще использую__attribute__((aligned(32))) после структуры. Я также меняю {0, __VA_ARGS__} на __VA_ARGS__, потому что хочу, чтобы _VA_ARGS содержал полный инициализатор {...}, и результат был в порядке. Есть ли причина, по которой вы добавляете к этому дополнительный 0? Я проверяю sizeof((int[]){}) и все компилируется нормально

Eric Sun 07.08.2024 10:02

Другие вопросы по теме