LINUX.ORG.RU

Как в ANSI C (99) разнести описание и определение статического константного массива?


0

0

Имеем:

typedef struct {
    int x, y;
} Wfrr;

static const Wfrr wfrr[] = {
    {1, 2},
    {3, 4},
/* тут _МНОГО_ элементов */
    {67, 68},
    {0, 0}
};

/* тут некоторый код, в котором используются данные из массива */
Неудобство этого кода в том, что массив занимает в начале файла много места и до кода нужно пролистать много экранов. Что хочется:
typedef struct {
    int x, y;
} Wfrr;

static const Wfrr wfrr[]; /* как это сделать?! */

/* тут некоторый код, в котором используются данные из массива */

static const Wfrr wfrr[] = {
    {1, 2},
    {3, 4},
/* тут _МНОГО_ элементов */
    {67, 68},
    {0, 0}
};
Как это сделать?

НЕ предлагать следующее:

  • Вынести массив в отдельный *.h or *.c+*.h.
  • s/static/extern/

Почему не предлагать? Потому что хочу странного =).

На данный момент массив вынесен в отдельный заголовочник.

Deleted

> На данный момент массив вынесен в отдельный заголовочник.

Это, наверное, самое разумное.

Можно в начале объявить static const Wfrr *wfrr; а в конце присвоить, но тогда нельзя будет смотреть sizeof(wfrr).

const86 ★★★★★
()

Хм, обычно, если массив действительно огромный - это означает, что он сгенерен автоматическим образом и тут сам бог велел выносить его, если не в отдельный включаемый файл, то в отдельную единицу компиляции уж точно, а потом просто линковаться с полученным объектным файлом. Если уж так сильно хочется странного, то можно, например, воспользоваться статическим константным указателем, проинициализировав его нужным образом перед использованием.

mannaz
()
Ответ на: комментарий от const86

Все равно для получения размера массива обычно вводится дополнительная статическая константа, не писать же все время sizeof(wfrr) / sizeof(Wfrr). Поэтому вполне разумно объявить вместе со static const Wfrr *wfrr также и static int wffrSize.

mannaz
()
Ответ на: комментарий от const86

> Можно в начале объявить static const Wfrr *wfrr; а в конце присвоить, но тогда нельзя будет смотреть sizeof(wfrr).

Можно конкретный пример, на который не будет ругаться компилятор?

Deleted
()
Ответ на: комментарий от mannaz

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

Да, он генерируется sed'ом и потом немного подправляется руками. В отдельный объектник выносить смысла нет, так как используется он всего в одном файле. Поэтому сделал инклудом.

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


То же самое: надо кусок кода, на который бы не ругался компилятор. Я как ни пробовал - компилятор говорит, что уже определено. Либо ещё какая-нибудь ошибка...

> Все равно для получения размера массива обычно вводится дополнительная статическая константа, не писать же все время sizeof(wfrr) / sizeof(Wfrr). Поэтому вполне разумно объявить вместе со static const Wfrr *wfrr также и static int wffrSize.


В моём случае это не нужно, так как это массив структур {const char *, int} и признаком конца является {NULL, 0}.

Deleted
()

в каком нибудь хэдере сделай так:

#define make_array(type, spec, name) \
spec type name[] = { /* тут содержание твоего массива */ };

потом заинклудь это в тот .с где тебе нужен массив, и сделай 

make_array (Wffr, static, wffr);

где нибудь в начале. Таким образом кишки массива будут в отдельном файле а объявлен он будет там где надо.

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

> в каком нибудь хэдере сделай так:

Гораздо проще весь массив в хедер запихнуть как есть. Что у меня и сделано. Я хочу решить проблему в рамках одного файла, как описал в первом посте.

Deleted
()
Ответ на: комментарий от summatus

> Wfrr* wfrr = (Wfrr*)arr();

Нужно на C (без плюсов). А в нём инициализировать можно только константами.

> return (void*)&wfrr;


Никто не гарантирует, что после выхода из функции wfrr всё ещё будет доступен.

Deleted
()
Ответ на: комментарий от Deleted

Ну тогда можно сделать свой двухпроходный препроцессор, который сначала парсит все директивы, а потом беспощадно заменяет все вхождения в файле (а не только те, которые встретились после определения директивы)

Тогда будет возможно

static Wffr wffr[] = DATA;

/* код который использует массив */

#lazydef DATA { /* содержание */ }


;)

yoghurt ★★★★★
()
Ответ на: комментарий от Deleted

ничего не понял, subj. компилуируется и работает, что надо автору?

>cat 1.c #include <stdio.h>

typedef struct { int x, y; } Wfrr;

static const Wfrr wfrr[]; /* как это сделать?! */

/* тут некоторый код, в котором используются данные из массива */

int main() { printf("wfrr[0].x %d\n", wfrr[0].x); return 0; }

static const Wfrr wfrr[] = { {1, 2}, {3, 4}, /* тут _МНОГО_ элементов */ {67, 68}, {0, 0} }; >gcc -std=c99 -Wall 1.c

fghj ★★★★★
()
Ответ на: комментарий от fghj

У меня в опциях компилятора стоит ещё -pedantic:

$ gcc -Wall -Wextra -std=c99 -pedantic test.c
test.c:5: error: array size missing in 'wfrr'
test.c:11: warning: excess elements in array initializer
test.c:11: warning: (near initialization for 'wfrr')
test.c:11: warning: excess elements in array initializer
test.c:11: warning: (near initialization for 'wfrr')
test.c:11: warning: excess elements in array initializer
test.c:11: warning: (near initialization for 'wfrr')

Deleted
()

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

Помести в конце файла. А в начале - extern.

Absurd ★★★
()
Ответ на: комментарий от Absurd

> Помести в конце файла. А в начале - extern.

!Ъ. Не хочу, чтобы wfrr был виден извне единицы трансляции. Нужно static.

Deleted
()
Ответ на: комментарий от Deleted

BoZo.c:

#include <stdio.h>

typedef struct {
    int x, y;
} Wfrr;

static const Wfrr wfrr[];

int main() {
        printf("%i, %i\n", wfrr[0].x, wfrr[1].x);
        return 0;
}

const Wfrr wfrr[] = {{1,2}, {3,4}};

Компилируем:

$gcc BoZo.c -o BoZo

Запускаем:

$./BoZo

1, 3

Absurd ★★★
()
Ответ на: комментарий от Absurd

> $gcc BoZo.c -o BoZo

Попробуй собрать с -pedantic.

Есть тут знатоки стандарта? Это всё-таки ограничение стандарта или ошибка в GCC?

Deleted
()
Ответ на: комментарий от Deleted

>У меня в опциях компилятора стоит ещё -pedantic: > >$ gcc -Wall -Wextra -std=c99 -pedantic test.c >test.c:5: error: array size missing in 'wfrr'

напиши размер, или удали -pedantic

fghj ★★★★★
()
Ответ на: комментарий от fghj

можно еще сделать так:

#include <stdio.h>

typedef struct {
    int x, y;
} Wfrr;

static const Wfrr *pwfrr;

/* тут некоторый код, в котором используются данные из массива */

int main()
{
	printf("wfrr[0].x %d\n", pwfrr[0].x);
	return 0;
}

static Wfrr wfrr[] = {
    {1, 2},
    {3, 4},
/* тут _МНОГО_ элементов */
    {67, 68},
    {0, 0}
};

static const Wfrr *pwfrr = &wfrr[0];

fghj ★★★★★
()
Ответ на: комментарий от Deleted

>Попробуй собрать с -pedantic.

После написания размера и добавления второго 'static' скомпилировалось с -pedantic -Wall. Хм, не знал. Думал что static & extern указывает компилятору на то что символ есть, но определен далее по тексту.

#include <stdio.h>

typedef struct { int x, y; } Wfrr;

static const Wfrr wfrr[2];

int main() { printf("%i, %i\n", wfrr[0].x, wfrr[1].x); return 0; }

const static Wfrr wfrr[] = {{1,2}, {3,4}};

Absurd ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.