#c #pointers #constants #final
#c #указатели #константы #Финал
Вопрос:
В Java мы можем указать строку как final
для объявления «констант». Например
static final String myConst = "Hello";
Правильный ли способ сделать это на c таким образом?
const char * const myConst = "Hello";
Я всегда видел, как люди делают это:
const char * myConst = "Hello";
Но, на самом деле, вы можете изменить то, на что указывает этот указатель. Итак, почему люди не объявляют указатель также константой? Каков правильный способ сделать это?
Комментарии:
1. нет, вы не можете изменить то, на что указывает указатель. Однако вы можете изменить указатель.
2. К вашему сведению, в C это следует читать наоборот.
const char * myConst
читается: «myConst — это указатель на символ, который является константой».const char * const myConst
читается как «myConst — это постоянный указатель на символ, который является постоянным».3. Большую часть времени вы видите этот последний вариант, тот, кто написал объявление, просто не знал ничего лучшего.
4. @Alexandre C. Да, именно это я и имел в виду. В том, что я ввел, есть некоторая двусмысленность. «Изменение того, на что указывает указатель», как при изменении значения указателя, не изменяя символьную строку.
Ответ №1:
const std::string myConst("Hello");
Комментарии:
1. Не забывайте о статической части. Для зеркального отображения Java это должна быть статическая переменная-член (хотя я полагаю, что global подойдет), поскольку у нее могут быть ограничения доступа, которые не были прояснены в вопросе.
2. @Martin: Ну, если бы это был статический элемент, его также нельзя было бы инициализировать в объявлении.
Ответ №2:
Да, const char* const
это правильный способ объявить строку в стиле C, которую вы не будете изменять.
Или лучше:
#include <string>
const std::string myConst = "Hello";
Ответ №3:
const char * myConst = "Hello";
Это означает, что объект, на который указано, не может измениться.
char * const myConst = "Hello";
Это означает, что местоположение, на которое указывает указатель, не может измениться, но значение объекта может.
const char * const myConst = "Hello";
Это означает, что ни то, ни другое не может измениться. По моему опыту, никто этого не помнит, но это всегда доступно в сети!
Как правило, три человека отвечают за то время, пока я пишу свой!
Комментарии:
1. @kriss Я думал, что в C существует неявное преобразование строкового литерала в
char*
для обратной совместимости с C.2. @kriss: второй вызовет предупреждение компилятора, если ваш компилятор является разумным, но не может вызвать ошибку, если ваш компилятор совместим, потому что это законный C по причине, указанной Марком.
3. С вами все в порядке, это более познавательно: char * const myConst = «H»;
4. @Mark @Steve: ок, предупреждение, только параноидальные типы вроде меня устанавливают -Werror по умолчанию 😉
5. @cbamber85: это разрешено и не отключает компилятор (поскольку вы все еще можете изменить указатель на строку).
Ответ №4:
Я не совсем понимаю ваш вопрос. Чтобы более или менее имитировать final
ключевое слово Java, это было бы либо
const char * const myConst = "Hello";
(если указатель не собирается меняться), и /или:
const char * myConst = "Hello";
если впоследствии указатель может измениться. Наконец, обратите внимание, что в первой версии вы фактически не можете изменить сам указатель, потому что он постоянный.
Ответ №5:
С учетом правки Диего, да, это правильный способ написания. Люди обычно не объявляют переменную const, потому что им все равно, будет ли она изменена, или, скорее, верят, что она не будет изменена (поскольку они знают, что не изменяют ее).
Они объявляют значение const, на которое указывают, потому что строковый литерал действительно содержит символы const, поэтому вы действительно должны присвоить его переменной, имеющей значения char const * .
Ответ №6:
Технически,
char * const myConst = "Hello";
это наиболее правильный ответ, поскольку при переназначении указателя вы получите строку, которая, вероятно, не может быть восстановлена.
Некоторые реализации позволяют изменять символы в «Hello» (даже если это плохая идея), поэтому первая константа в
char const * const myConst = "Hello";
Отличная идея. Лично как
char const * myConst = ...;
и
const char * myCount = …;
эквивалентны, я склонен применять руководство по стилю, согласно которому const всегда следует за элементом, который он изменяет. Иногда это уменьшает количество заблуждений в долгосрочной перспективе.
Тем не менее, большинство людей не знают, как const
правильно использовать C , поэтому он либо используется плохо, либо не используется вообще. Это потому, что они просто используют C как улучшенный компилятор C.
Комментарии:
1. char * const myConst = «Hello»; Это не определяет постоянную C-строку. Это взлом, который C допускает для совместимости с C. Вы присваиваете строковый литерал указателю на неконстантную строку. Конечно, каждый компилятор должен разрешать операции изменения, например myConst[2] = ‘a’; что также является неопределенным поведением.
2. @Gene Bushuyev: Почему вы говорите, что
myConst[2] = 'a';
это неопределенное поведение?'a'
это просто сокращение для установки значения в числовом типе char (просто еще один способ записиmyConst[2] = 97;
в среде ASCII). Какого черта установка 97 в массиве будет иметь неопределенное поведение?
Ответ №7:
Но, на самом деле, вы можете изменить то, на что указывает этот указатель. Итак, почему люди не объявляют указатель также константой? Каков правильный способ сделать это?
Поскольку это редко бывает полезно, чаще всего вам хотелось бы, чтобы значения в стеке (включая указатели) были неконстантными. Возьмите книгу Саттера и Александреску «Стандарты кодирования», в ней объясняется этот момент.
Ответ №8:
Реальный смысл заключается в том, что программисты вынуждены объявлять некоторые указатели, по крайней мере, как const char *
для хранения массивов символов между двойными кавычками. Ничто не заставляет их (никаких предупреждений компилятора или ошибок) также делать указатель постоянным … поскольку люди ленивы, вы можете сделать свой собственный вывод. Вероятно, они на самом деле даже не пытаются определить константу, они просто хотят отключить ошибки компилятора (ну, предупреждение в данном случае).
Имея это в виду, я бы, вероятно, в любом случае выбрал другое решение:
const char myConst[] = "Hello";
Разница здесь в том, что таким образом я не буду разлагать исходный массив байтов, используемый в качестве строки, на указатель, у меня все равно останется массив байтов, который можно использовать точно как исходный литерал.
С его помощью я могу делать что-то вроде sizeof(myConst)
и получать тот же результат, что и с sizeof("Hello")
. Если я изменю строку на указатель, sizeof вернет размер указателя, а не размер строки…
… и очевидно, что при выполнении таких действий изменение указателя становится бессмысленным, поскольку указателя для изменения больше нет.