2016-11-06 3 views
1

Допустим, у меня есть два статически выделенные глобальные массивы:Создание статически выделяемый массив из двух массивов

const int foo[] = {1, 2, 3}; 
const int bar[] = {4, 5, 6, 7}; 

Позже на той же единице компиляции, которые я хотел, чтобы объявить массив, который также статически выделяется и конкатенация foo и bar:

const int foo_and_bar[] = ... ? 

Возможно или нет?

Конечно, я мог бы сделать что-то уродливое с макросами, как ...

#define FOO_CONTENTS 1, 2, 3 
#define BAR_CONTENTS 4, 5, 6, 7 

const int foo[] = {FOO_CONTENTS}; 
const int bar[] = {BAR_CONTENTS}; 

const int foo_and_bar[] = {FOO_CONTENTS, BAR_CONTENTS}; 

... но я ищу поддерживаемые идиомы в самом языке C.

+0

«действительно уродливый», что не так с этим элегантным и чрезвычайно простым решением? – Leushenko

+0

Возможно, я мог бы просто сказать «уродливый» - «действительно уродливый» может быть преувеличением! Это уродливо, потому что каждое объявление массива нужно разделить на макрос и декларацию, а не просто выражать «этот массив должен содержать содержимое двух других ранее объявленных переменных». Чтение кода является более жестким, потому что вам нужно расшифровать макрос и найти его в файле и т. Д. Конечно, многие другие сценарии в этих строках (помещая статически выделенные ints в массивы и т. Д.) Не нуждаются в поддержке препроцессора. – BeeOnRope

ответ

1

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

Всех выражения в инициализаторе для объекта, который имеет статический или нить срока хранения должна быть константными выражениями или строковые литералов.

(6.7.9 p4)

Массива-индекс [] и член доступ . и -> операторов, адрес & и косвенность * унарные, и указатель слепки может быть использован в создании постоянный адрес, но значение объекта не должно быть доступно при использовании этих операторов.

(6.6 p9)

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

+0

Хотя я надеялся на «вы можете!» ответ, это выглядит примерно так же окончательно, как и для «вы не можете». – BeeOnRope

-2
Yup! you can create another array whose size is the sum of both foo and bar . Then you can one by one copy the elements using looping statements. first loop will begin from 0 to the size of first array and second loop will begin from the size of first array to the size of the second array. 
1

Вот альтернативный подход:


Поскольку все три массива только для чтения, вы можете также выделить только один из них:

const int foo_and_bar[] = {1,2,3,4,5,6,7}; 

Тогда, используйте дополнительные переменные, указывающие индекс и размер каждой подматрицы:

int fooIndex = 0, fooSize = 3; 
int barIndex = 3, barSize = 4; 
+0

Да, это было бы разумно в зависимости от случая использования. Если мне нужно использовать массив в месте, ожидающем массив, и я не могу изменить его поведение, он не будет работать. Есть также некоторые интересные вещи, которые вы можете сделать со статическими массивами, которые вы не можете с помощью простых указателей, таких как 'sizeof (array)', чтобы получить счет. – BeeOnRope

+0

@BeeOnRope: Что вы подразумеваете под «изменением поведения» ??? –

+0

Я имею в виду, что если я хочу использовать этот массив в каком-то коде, ожидается полный массив, а не указатель и размер (или массив, смещение и размер), я не смогу, если только я не смогу изменить этот код, t обязательно возможно или желательно. – BeeOnRope

1

Проблема в том, что все переменные продолжительности статического хранения работают с списками инициализаторов, которые должны быть константами времени компиляции, как определено языком.Другая переменная, даже если объявлена ​​как const, не считается постоянной времени компиляции. Кроме того, вы не можете инициализировать или напрямую назначать массив из другого массива.

Поэтому вы не можете этого сделать из-за ограничений на языке. Ваша версия с #defines для списков инициализаций на самом деле является общим решением. Это простое решение, поэтому оно может быть лучшим.


Если вы ищете способ доступа к данным по-разному, один альтернатива может быть что-то с профсоюзами и C11 анонимных структурами:

#include <stdio.h> 

#define FOO_INIT 1, 2, 3 
#define BAR_INIT 4, 5, 6, 7 

#define FOO_SIZE (sizeof((int[]){ FOO_INIT })/sizeof(int)) 
#define BAR_SIZE (sizeof((int[]){ BAR_INIT })/sizeof(int)) 

typedef union 
{ 
    int array [FOO_SIZE + BAR_SIZE]; 
    struct 
    { 
    int foo [FOO_SIZE]; 
    int bar [BAR_SIZE]; 
    }; 
} foobar_t; 



int main (void) 
{ 
    static const foobar_t foobar = { .foo = {FOO_INIT}, .bar = {BAR_INIT} }; 

    // print 1 2 3 4 5 6 7 
    for(size_t i=0; i<FOO_SIZE + BAR_SIZE; i++) 
    { 
    printf("%d ", foobar.array[i]); 
    } 
} 

Теперь, если вы хотите, чтобы сделать твердую копию массив (ы), вы можете просто сделать foobar_t foobar2 = foobar;. C довольно странно, потому что, хотя он не позволяет назначать массивы, он отлично справляется с назначением структур/объединений, содержащих массивы. (Но это все равно не будет работать, если foobar2 имеет статическую продолжительность хранения.)

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