Определение константных значений в C - PullRequest
5 голосов
/ 10 декабря 2008

У меня есть проект C, в котором весь код организован в пары файлов *.c / *.h, и мне нужно определить постоянное значение в одном файле, которое, однако, будет также использоваться в других файлах. Как мне объявить и определить это значение?

Должно ли оно быть как static const ... в файле *.h? Как extern const ... в файле *.h и определено в файле *.c? Каким образом имеет значение, является ли значение не примитивным типом данных (int, double и т. Д.), А char * или struct? (Хотя в моем случае это double.)

Определение содержимого внутри *.h файлов вообще не кажется хорошей идеей; нужно объявить вещи в файле *.h, но определить их в файле *.c. Тем не менее, подход extern const ... кажется неэффективным, так как компилятор не сможет встроить значение, вместо этого ему все время нужно обращаться по его адресу.

Полагаю, суть этого вопроса такова: нужно ли определять static const ... значения в *.h файлах на C, чтобы использовать их в более чем одном месте?

Ответы [ 10 ]

8 голосов
/ 10 декабря 2008

Правило, которое я соблюдаю, - объявлять вещи только в файлах H и определять их в файлах C. Вы можете объявить и определить в одном файле C, при условии, что он будет использоваться только в этом файле.

Под объявлением я подразумеваю уведомлять компилятор о его существовании, но не выделяю для него место. Это включает #define, typedef, extern int x и т. Д.

Определения присваивают значения объявлениям и выделяют для них место, например int x и const int x. Это включает определения функций; включение их в заголовочные файлы часто приводит к потере пространства кода.

Я видел, как слишком много начинающих программистов смущаются, когда они помещают const int x = 7; в заголовочный файл, а затем удивляются, почему они получают ошибку ссылки для x, определяемой более одного раза. Я думаю, что как минимум вам понадобится static const int x, чтобы избежать этой проблемы.

Я бы не слишком беспокоился о скорости кода. Основная проблема с компьютерами (с точки зрения скорости и стоимости) давно перешла от скорости выполнения к простоте разработки.

3 голосов
/ 11 декабря 2008

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

enum {
    FOO_SIZE = 1234,
    BAR_SIZE = 5678
};

#define FOO_SIZE 1234
#define BAR_SIZE 5678

static const int FOO_SIZE = 1234;
static const int BAR_SIZE = 5678;

В C ++ я склонен использовать способ enum, поскольку он может быть ограничен пространством имен. Для C я использую макрос. Это в основном сводится к вопросу вкуса, хотя. Если вам нужны константы с плавающей запятой, вы больше не можете использовать перечисление. В C ++ я использую последний способ, статический const double, в этом случае (примечание в C ++ static будет избыточным тогда; они станут статическими автоматически, так как они являются const). В Си я бы продолжал использовать макросы.

Это миф , что использование третьего метода замедлит вашу программу в любом случае. Я просто предпочитаю перечисление, так как значения, которые вы получаете, являются rvalues ​​- вы не можете получить их адрес, который я считаю дополнительной безопасностью. Кроме того, написано гораздо меньше кода. Глаз сосредоточен на константах.

1 голос
/ 10 декабря 2008

Как правило, вы не определяете вещи как static в заголовке. Если вы определяете static переменные в заголовке, каждый файл, который использует заголовок, получает свою собственную частную копию того, что объявлено static, что является противоположностью принципа DRY : don ' повторить себя .

Итак, вы должны использовать альтернативу. Для целочисленных типов использование enum (определено в заголовке) очень эффективно; он хорошо работает и с отладчиками (хотя лучшие отладчики также могут помочь с макро значениями #define). Для нецелочисленных типов наилучшим способом обычно является объявление extern (необязательно квалифицированное const) в заголовке и одно определение в одном C-файле.

1 голос
/ 10 декабря 2008

Вам действительно нужно беспокоиться о преимуществе inline? Если вы не пишете встроенный код, придерживайтесь удобочитаемости. Если это действительно магическое число чего-то, я бы использовал определение; Я думаю, что const лучше для таких вещей, как строки версий const и изменение аргументов вызова функции. Тем не менее, определение в .c, объявление в .h правило, безусловно, является общепризнанным соглашением, и я бы не нарушал его только потому, что вы могли бы сохранить поиск в памяти.

0 голосов
/ 11 декабря 2008

В C ++ вы всегда должны использовать

const int SOME_CONST = 17;

для констант и никогда

#define SOME_CONST 17

Определения почти всегда возвращаются и кусают вас позже. Консты на языке и строго типизированы, поэтому вы не получите странных ошибок из-за некоторого скрытого взаимодействия. Я бы положил const в соответствующий заголовочный файл. Пока это #pragma один раз (или #ifndef x / #define x / #endif), вы никогда не получите никаких ошибок компиляции.

В vanilla C у вас могут быть проблемы с совместимостью, где вы должны использовать # define.

0 голосов
/ 10 декабря 2008

Чтобы ответить на суть вашего вопроса:
Вы обычно НЕ хотите определить статическую переменную в заголовочном файле.
Это может привести к дублированию переменных в каждой единице перевода (файлы C), которые содержат заголовок.

переменные в заголовке действительно должны быть объявлены extern, поскольку это подразумеваемая видимость. См. этот вопрос для хорошего объяснения.

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

0 голосов
/ 10 декабря 2008

для среды autoconf: Вы также всегда можете определить константы в файле конфигурации. AC_DEFINE () я думаю, это макрос для определения во всей сборке.

0 голосов
/ 10 декабря 2008

Если вы хотите встроить значение в свои функции, вы должны использовать #define MY_MAGIC_NUMBER 0x12345678
Даже static const unsigned MY_MAGIC_NUMBER = 0x12345678 приведет к получению значения с адреса. Нарушение производительности не будет иметь большого значения, если вы не будете много ценить в циклах.
Я использую const только для аргументов функции.

Было несколько комментариев и отрицательных ответов по этому ответу, поэтому я проверил свое предположение и просмотрел сгенерированную сборку, и этот ответ неверный. В основном #define и const дадут одинаковый результат.

0 голосов
/ 10 декабря 2008

Я бы хотел увидеть больше контекста для вашего вопроса. Тип значения имеет решающее значение, но вы оставили его. Значение ключевого слова const в C довольно тонкое; например const char * p; не означает, что указатель p является константой; Вы можете написать р все, что вам нравится. Что вы не можете написать, так это память, на которую указывает p, и это остается верным даже при изменении значения p. Это единственный случай, который я действительно понимаю; в общем, смысл тонкого размещения констант мне не понятен. Но этот особый случай чрезвычайно полезен для параметров функции , поскольку он извлекает обещание из функции, что память, на которую указывает аргумент, не будет видоизменяться.

Есть еще один особый случай, который должен знать каждый: целые числа. Почти всегда постоянные именованные целые числа должны быть определены в файле .h как литералы перечисления . Типы enum не только позволяют естественным образом группировать связанные константы, но и позволяют видеть имена этих констант в отладчике, что является огромным преимуществом.

Я написал десятки тысяч строк C; вероятно сотни, если я попытаюсь выследить это. (wc ~ / src / c / *. c говорит о 85 тысячах, но кое-что из этого генерируется, и, конечно, есть много кода на C, скрывающегося в другом месте). Помимо двух случаев, я никогда не нашел большого использования для const. Я был бы рад узнать новый, полезный пример.

0 голосов
/ 10 декабря 2008

Я могу дать вам косвенный ответ. В C ++ (в отличие от C) const подразумевает static. То есть в C ++ static const это то же самое, что и const. Таким образом, это говорит вам о том, как это тело стандартов C ++ относится к проблеме, то есть все const s должны быть статическими.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...