Подтвердить что ты не робот

Должен ли я использовать константы над определениями?

В C, я должен предпочесть константы над определениями? В последнее время я читаю много кода, и все примеры сильно используют определения.

4b9b3361

Ответ 1

Нет, в общем случае вы не должны использовать объекты const, созданные в C, для создания констант имен. Чтобы создать именованную константу в C, вы должны использовать либо макросы (#define), либо перечисления. На самом деле, язык C не имеет констант, в том смысле, что вы, кажется, подразумеваете. (C в этом отношении существенно отличается от С++)

В языке C понятия константного и постоянного выражения определяются очень иначе, чем С++. В константе C подразумевается буквальное значение, например 123. Вот несколько примеров констант в C

123
34.58
'x'

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

Например, следующее не является константой

const int C = 123; /* C is not a constant!!! */

и поскольку вышеуказанный C не является константой, он не может использоваться для объявления типа массива в области видимости файла

typedef int TArray[C]; /* ERROR: constant expression required */

Его нельзя использовать как метку case

switch (i) {
  case C: ; /* ERROR: constant expression required */
}

Его нельзя использовать в качестве ширины битового поля

struct S {
  int f : C; /* ERROR: constant expression required */
};

Он не может использоваться как инициализатор для объекта со статической продолжительностью хранения

static int i = C; /* ERROR: constant expression required */

Он не может использоваться в качестве инициализатора перечисления

enum {
  E = C /* ERROR: constant expression required */
};

i.e его нельзя использовать везде, где требуется константа.

Это может показаться контр-интуитивным, но именно так определяется язык C.

Вот почему вы видите эти многочисленные #define -s в коде, с которым работаете. Опять же, на языке C объект, имеющий const, имеет очень ограниченное использование. Они в основном совершенно бесполезны как "константы", поэтому на языке C вы в основном вынуждены использовать #define или перечисления для объявления истинных констант.

Конечно, в ситуациях, когда для вас работает объект, соответствующий const, т.е. он делает то, что вы хотите, он действительно превосходит макросы разными способами, так как он скопирован и напечатан. Вероятно, вам следует предпочесть такие объекты, где это применимо, однако в общем случае вам придется учитывать вышеуказанные ограничения.

Ответ 2

Константы должны быть предпочтительнее define s. Существует несколько преимуществ:

  • Тип безопасности. В то время как C является слабо типизированным языком, использование define теряет всю безопасность типа, что позволит компилятору подобрать проблемы для вас.

  • Простота отладки. Вы можете изменить значение констант через отладчик, в то время как define автоматически изменяется в коде препроцессором на фактическое значение, а это означает, что если вы хотите изменить значение для целей тестирования/отладки, -compile.

Ответ 3

Возможно, я использовал их неправильно, но, по крайней мере, в gcc, вы не можете использовать константы в операторах case.

const int A=12;
switch (argc) {
    case A:
    break;
}

Ответ 4

Многие люди здесь дают вам совет "С++ style". Некоторые даже говорят, что аргументы С++ применимы к C. Это может быть справедливым моментом. (Является ли это или нет чувствует себя субъективным.) Люди, которые говорят const, иногда означают, что что-то другое на двух языках также правильно.

Но это в основном незначительные моменты и лично, я думаю, что в действительности есть относительно незначительные последствия для любого пути. Это вопрос стиля, и я думаю, что разные группы людей дадут вам разные ответы.

С точки зрения общего использования, исторического использования и наиболее распространенного стиля в C, более типично видеть #define. Использование С++-isms в C-коде может быть столь же странным для некоторого узкого сегмента C-кодеров. (Включая меня, чтобы там лежали мои предубеждения.)

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

Ответ 5

Хотя этот вопрос специфичен для C, я думаю, хорошо это знать:

#include<stdio.h>
int main() {
    const int CON = 123;
    int* A = &CON;
    (*A)++;
    printf("%d\n", CON);  // 124 in C
}

работает в C, но не в С++

Одна из причин использования #define заключается в том, чтобы избежать таких вещей, чтобы испортить ваш код, особенно это сочетание C и С++.

Ответ 6

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

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

  • директивный переключатель
  • замена исходной строки
  • макросы кода

Пример, когда вы должны использовать define over const, - это когда у вас есть номер версии say 3, и вы хотите, чтобы версия 4 включала некоторые методы, недоступные в версии 3

#define VERSION 4
...

#if VERSION==4
   ................
#endif 

Ответ 7

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

Константы имеют тип, а также значение, поэтому они предпочли бы, когда имеет смысл для вашего значения иметь тип, но не тогда, когда он является бесприбыльным (или полиморфным).

Ответ 8

Если это программно не определено, я использую #define. Например, если я хочу, чтобы все объекты моего UI имели одинаковое пространство между ними, я мог бы использовать #define kGUISpace 20.

Ответ 9

Помимо превосходных причин, которые AndreyT использует для использования DEFINES, а не констант в коде "C", существует еще одна прагматическая причина использования DEFINES.

DEFINES легко определить и использовать файлы заголовков (.h), в которых любой опытный C-кодер будет искать найденные константы. Определение consts в файлах заголовков не так просто - его больше кода, чтобы избежать дублирования определений и т.д.

Также аргументы "typafe" являются спорными. Большинство компиляторов будут воспринимать вопиющие ошибки, такие как определение строки и int, или "сделают правильную вещь" при небольшом рассогласовании, например, присваивая целочисленное значение float.

Ответ 10

Макросы (определения) могут использоваться препроцессором и во время компиляции константы не могут.

Вы можете выполнять проверки времени компиляции, чтобы убедиться, что макрос находится в допустимом диапазоне (и #error или #fatal, если это не так). Вы можете использовать значения по умолчанию для макроса, если они еще не определены. Вы можете использовать макрос в размере массива.

Компилятор может оптимизировать с помощью макросов лучше, чем он может с константами:

const int SIZE_A = 15;
#define SIZE_B 15

for (i = 0; i < SIZE_A + 1; ++i);    // if not optimized may load A and add 1 on each pass
for (i = 0; i < SIZE_B + 1; ++i);    // compiler will replace "SIZE_B + 1" with 16

Большая часть моей работы связана со встроенными процессорами, у которых нет потрясающих оптимизационных компиляторов. Возможно, gcc будет рассматривать SIZE_A как макрос на определенном уровне оптимизации.