При просмотре кода я применяю следующие правила:
Всегда используйте const
для параметров функции, передаваемых по ссылке, когда функция не изменяет (или не освобождает) указанные данные.
int find(const int *data, size_t size, int value);
Всегда используйте const
константы, которые в противном случае могут быть определены с помощью #define или enum. В результате компилятор может размещать данные в постоянном запоминающем устройстве (ПЗУ) (хотя компоновщик часто является лучшим инструментом для этой цели во встроенных системах).
const double PI = 3.14;
Никогда не используйте const в прототипе функции для параметра, переданного по
значению . Это не имеет смысла и, следовательно, просто «шум».
// don't add const to 'value' or 'size'
int find(const int *data, size_t size, const int value);
При необходимости используйте const volatile
в местах, которые не могут быть изменены программой, но могут измениться. Аппаратные регистры являются типичным случаем использования, например, регистр состояния, который отражает состояние устройства:
const volatile int32_t *DEVICE_STATUS = (int32_t*) 0x100;
Другое использование не является обязательным. Например, параметры функции в реализации функции могут быть помечены как const.
// 'value' and 'size can be marked as const here
int find(const int *data, const size_t size, const int value)
{
... etc
или функция возвращает значения или вычисления, которые получены и затем никогда не изменяются:
char *repeat_str(const char *str, size_t n)
{
const size_t len = strlen(str);
const size_t buf_size = 1 + (len * n);
char *buf = malloc(buf_size);
...
Это использование const
просто указывает, что вы не будете изменять переменную; они не меняют то, как и где хранится переменная. Разумеется, компилятор может определить, что переменная не изменилась, но, добавив, const
вы позволите этому принудительно применить это. Это может помочь читателю и добавить некоторую безопасность (хотя, если ваши функции большие или достаточно сложные, что это имеет большое значение, у вас, возможно, есть другие проблемы). Редактировать - например плотно закодированная функция из 200 строк с вложенными циклами и множеством длинных или похожих имен переменных, зная, что некоторые переменные никогда не меняются, может значительно облегчить понимание. Такие функции были плохо разработаны или поддерживаются.
Проблемы с const
. Вы, вероятно, услышите термин «отравление константой». Это происходит, когда добавление const
к параметру функции вызывает распространение «constness».
Редактировать - постоянное отравление: например, в функции:
int function_a(char * str, int n)
{
...
function_b(str);
...
}
если мы изменим str
на const
, мы должны затем убедиться, что fuction_b
также принимает const
. И так далее , если function_b
проходит str
на function_c
, и т.д. Как вы можете себе представить , что это может быть болезненным , если она распространяется на множество отдельных файлов / модулей. Если он распространяется в функцию, которую нельзя изменить (например, в системную библиотеку), тогда приведение становится необходимым. Таким образом, разбрасывание
const
в существующем коде, возможно, вызывает проблемы. В новом коде, однако, лучше всего const
квалифицироваться последовательно, где это уместно.
Более коварная проблема в const
том, что это не на языке оригинала. Как дополнение это не совсем подходит. Для начала у этого есть два значения (как в правилах выше, означающих "я не собираюсь изменять это" и "это не может быть изменено"). Но более того, это может быть опасно. Например, скомпилируйте и запустите этот код и (в зависимости от компилятора / опций) он может привести к сбою при запуске:
const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = '\0';
strchr
возвращает char*
не const char*
. Поскольку его параметр вызова -
const
это, он должен привести параметр вызова к char*
. И в этом случае это отбрасывает реальное свойство хранения только для чтения. Изменить: - это обычно относится к переменным в памяти только для чтения. Под «ПЗУ» я имею в виду не только физическое ПЗУ, но и любую память, защищенную от записи, как это происходит с разделом кода программ, работающих на типичной ОС.
Многие стандартные библиотечные функции ведут себя одинаково, поэтому будьте осторожны: когда у вас есть реальные константы (т.е. хранятся в ПЗУ), вы должны быть очень осторожны, чтобы не потерять их константу.
Specific issues with software development
. Я весьма конкретен.