2016-07-15 3 views
6

У меня есть макрос повторить макрос, который я использую, чтобы заполнить массивы со значениями по умолчанию во время компиляции:C макроподстановка заказ

const int array [512] = 
{ 
    MACRO_REPEAT(512, -2) // this repeats -2, 512 times 
    [4] = 10, 
    [5] = 2, 
    ... 
} 

Макроса повтора будет расширяться MACRO_REPEAT_512, но теперь я хотел бы использовать другие макросы как размер массива, как:

#define ARRAY_LENGTH 512 
const int array [ARRAY_LENGTH ] = 
{ 
    MACRO_REPEAT(ARRAY_LENGTH , -2) // this repeats -2, 512 times 
    [4] = 10, 
    [5] = 2, 
    ... 
} 

Но это расширяющееся к MACRO_REPEAT_ARRAY_LENGTH, не расширяет ARRAY_LENGTH значения до конкатенации его. Другой пример будет для многомерных массивов, что предполагает более уровней расширения:

#define X 512 
#define Y 512 

const int array [X][Y] = 
{ 
    MACRO_REPEAT(X*Y , -2) // this repeats -2, 512 times 
    [4] = 10, 
    [5] = 2, 
    ... 
} 

Это будет расширяться MARO_REPEAT_X * Y. Итак, есть ли способ расширить эти значения до конечного числового значения, прежде чем конкатенировать его с другими макросами?

+0

Почему бы просто не использовать цикл или 'memset()'? Да, они работают во время выполнения, но достигают желаемого эффекта относительно легко. – Peter

+2

GCC имеет расширение, которое позволяет инициализировать диапазон элементов с тем же значением, что-то вроде 'int array [ARRAY_LENGTH] = {[0 ... 3] = -2, [4] = 10, [5] = 2, [6 ... ARRAY_LENGTH - 1] = -2,}; ' –

+1

@Peter Я знаю это, но я работаю во встроенной системе, и я хотел бы сохранить его во flash (обновленный вопрос с помощью определителя константы) – rnunes

ответ

1

Вы можете решить вопрос MACRO_REPEAT(ARRAY_LENGTH , -2), изменив определение «MACRO_REPEAT» на использование двухэтапного расширения, то есть не используйте в качестве тонера в MACRO_REPEAT, вызовите другой макрос, который делает.

Не то, что это будет работать, как ожидалось, если ARRAY_LENGTH определен как токен с одним номером, и если есть определение макроса для этого конкретного размера.

Вы не можете обработать более общий корпус MACRO_REPEAT(X*Y , -2) со стандартным препроцессором C.

Вы можете использовать GCC расширения для инициализации простых массивов:

#define MACRO_REPEAT(n, e) [ 0 ... (n)-1 ] = (e), 

Но этот метод не может быть использован для обработки многомерных массивов, таких как MACRO_REPEAT(X*Y , -2).

Вы можете попробовать это:

#define MACRO_REPEAT(n, e) [ 0 ... (n)-1 ] = (e), 
#define X 512 
#define Y 512 

const int array[X][Y] = { MACRO_REPEAT(X, { MACRO_REPEAT(Y, -2) }) }; 

Но использование C препроцессором только запутывает намерение. Если вы решите полагаться на расширения gcc, просто используйте их напрямую.

+0

Я знаю, но многомерный массив с X-столбцами и Y-строками, это просто еще один способ увидеть массив одномерных измерений X * Y. Я считаю, что вы можете делать такие вещи, как int array [1] [2] = {first, second} и сначала будут сохранены в [0] [0], а в другом - в [0] [1] – rnunes

+0

@munes: вы правы : если вы можете развернуть макрос до последовательности инициализаторов 262144, он будет работать. Попробуйте 'MACRO_REPEAT (512, {MACRO_REPEAT (512, -2)})' с вашим текущим определением макроса. – chqrlie

+0

@chqrlie не компилирует https://ideone.com/1GQf9N – 4pie0

1

Я не уверен, что это считается «правильным» ответом, поскольку он не отвечает непосредственно на вопрос OP, но это является рекомендуемым решением проблемы. Он также не является стандартным C, поскольку он использует расширение GCC.

В компиляторе GNU C (gcc) ряд элементов массива может быть инициализирован с тем же значением, используя форму [FIRST ... LAST] = VALUE. Кроме того, по-видимому, позволит более чем одним инициализатора для элемента, так что можно инициализировать диапазон элементов в том же значении, а затем инициализировать элементы, содержащиеся в пределах этого диапазона до различных значений, что-то вроде этого:

#define ARRAY_LENGTH 512 
const int array[ARRAY_LENGTH] = 
{ 
    [0 ... ARRAY_LENGTH - 1] = -2, 
    [4] = 10, 
    [5] = 2, 
    /* ... */ 
}; 
+0

Вы знаете, что вы правы в этом вопросе, не являясь ответом на исходный вопрос (поэтому он сделал его более широким). извините за запрос репоста, chqrlie ответьте, что он ближе к правильному ответу – rnunes

Смежные вопросы