Когда и для каких целей следует использовать ключевое слово const в C для переменных?

softwareengineering.stackexchange https://softwareengineering.stackexchange.com/questions/204500

Вопрос

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

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

  • Следует ли его использовать для большей ясности в прототипах функций?
  • Следует ли это использовать в качестве меры безопасности при разработке кода?
  • Должен ли он использоваться в рамках различных функций для объявления констант времени выполнения?
  • Стоит ли его вообще использовать?

Эти вопросы - всего лишь примеры путаницы, с которой я сталкиваюсь.Общая путаница заключается в следующем

  • Когда должен быть const ключевое слово, используемое в программировании на языке Си?
  • Каковы различные виды преимуществ, которые можно получить, используя это ключевое слово в C?
  • Есть ли какие-либо минусы в использовании const ключевое слово?


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

Когда и для каких целей следует использовать ключевое слово const в C для переменных?

Это также можно перефразировать следующим образом

Правильное использование const ключевое слово в C` с одинаковыми плюсами и минусами.

Это было полезно?

Решение

При просмотре кода я применяю следующие правила:

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

    int find(const int *data, size_t size, int value);
    
  • Всегда используйте const для констант, которые в противном случае могли бы быть определены с помощью #define или enum.В результате компилятор может найти данные в памяти, доступной только для чтения (ROM) (хотя компоновщик часто является лучшим инструментом для этой цели во встроенных системах).

    const double PI = 3.14;
    
  • Никогда не используйте const в функции прототип для параметра, переданного значение.Это не имеет никакого значения и, следовательно, является просто "шумом".

    // don't add const to 'value' or 'size'
    int find(const int *data, size_t size, 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 также требуется a 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*.И в этом случае это отбрасывает реальное свойство хранилища, доступное только для чтения. Редактировать:- обычно это относится к переменным в памяти, доступной только для чтения.Под "ПЗУ" я подразумеваю не только физическое ПЗУ, но и любую память, защищенную от записи, как это происходит с разделом кода программ, запускаемых в обычной ОС.

Многие стандартные библиотечные функции ведут себя точно так же, так что будьте осторожны:когда у вас есть реальный константы (т.е.хранятся в ПЗУ), вы должны быть очень осторожны, чтобы не потерять их постоянство.

Другие советы

Generally in any programming language its recommended to use const or the equivalent modifier since

  • It can clarify to the caller that what they passed in is not going to change
  • Potential speed improvements since the compiler knows for certain it can omit certain things that are only relevant if the parameter can change
  • Protection from yourself accidentally changing the value

In agreement with TheLQ's statements:

When working with a team of programmers declaring const is a good way of indicating that said variable shouldn't be modified, or just for reminding yourself in large projects. It's useful in that sense, and can save many headaches.

Yes, it's basically the TheLQ's answer.

Is a security measure for the programmer so you don't modify a variable, and to not call functions that may modify them. In an array or structure the const specifier indicates that the values of their contents won't be modified, and even the compiler will not allow you to do so. You still can easily change the value of the variable with just a cast however.

In what I have usually see, it's mostly used to add constant values in code, and to indicate that the array or structure won't be modified if you call a particular function. This last part is important, because when you call a function that WILL modify your array or structure, you may want to keep the original version, so you create a copy of the variable and then pass it to function. If that is not the case, you don't require the copy, obviously, so for example you can change,

int foo(Structure s);

to

int foo(const Structure * s);

and not getting the copy overhead.

Just to add, note that C has particular rules with the const specifier. For example,

int b = 1;
const int * a = &b;

is not the same as

int b = 1;
int * const a = &b;

The first code won't allow you to modify a. In the second case, the pointer is constant but its contents is not, so the compiler will allow you to say * a = 3; without a compiler error, but you can't make a to be a reference to another thing.

Лицензировано под: CC-BY-SA с атрибуция
scroll top