Как сделать переменную константой c
Константа, переменная — это базовые понятия в любом языке программирования. Дадим им определения.
Константа — это величина, которая при выполнении программы остаётся неизменной.
Переменная — это ячейка памяти для временного хранения данных. Предполагается, что в процессе выполнения программы значения переменных могут изменяться.
Описание и инициализация переменных
Прежде чем использовать в программе какую-то переменную, надо дать ей описание , то есть сказать, какое имя имеет переменная и каков её тип. Вначале указывается тип переменной, а затем её имя. Например:
int k; // это переменная целого типа int
double x; // это переменная вещественного типа удвоенной точности
Если имеется несколько переменных одного типа, то допускается их описание через запятую в одном операторе, например:
После описания переменной её можно использовать, но возникает вопрос: а какое значение имеет переменная сразу же после её описания? Ответ таков: в программе на языке C или C++ переменная после описания имеет произвольное значение , то есть ей просто выделяется свободный участок памяти и на этом всё заканчивается. В переменной хранится та последовательность двоичных цифр, которая была там до выделения памяти под эту переменную. Такой подход таит определённую опасность: можно по ошибке использовать в выражении переменную, которой не было присвоено ни какое значение:
Так как переменная x ни как не была определена, т. е. имела произвольное значение (чаще всего — это очень большое число или наоборот — очень маленькое), то и переменная y получит явно не то значение, на которое рассчитывал пользователь.
Чтобы избежать такой ошибки, Бьерн Страуструп рекомендует инициализировать переменные , то есть не просто выделять память под переменные, но и задавать им при этом необходимые значения. Например:
double a=3, b=4, c=5;
Инициализация переменных выполняется один раз на этапе компиляции, она не снижает скорость работы программы, но при этом уменьшает риск использования переменной, которая не получила ни какого значения.
Задание и использование констант
Выше было дано определение констант. Теперь рассмотрим работу с константами более подробно.
Все константы вне зависимости от типа данных можно подразделить на две категории: именованные константы и константы, которые не имеют собственного имени. Например:
25 — константа целого типа;
3.14 — вещественная константа;
‘A’ — символьная константа.
Все три приведённые здесь константы не имеют имени, они заданы своим внешним представлением и используются в программе непосредственно, например так:
int k=25; // переменная k инициализирована константой — целым числом 25.
В ряде случаев константе удобнее дать имя и использовать её далее по имени. Обычно это делается для математических или физических констант.
В языке C был единственный способ создания именованных констант — с помощью директивы препроцессора #define , например:
t = PI * 2; // здесь использована именованная константа PI, заданная выше
В языке C++ появился ещё один способ — использование константных переменных , то есть переменных, которые нельзя изменять после инициализации. Рассмотрим на том же примере:
const double PI=3.14; // здесь PI — константная переменная
В чём преимущество от использования константных переменных вместо задания констант с помощью директивы препроцессора #define ? Всё очень просто: при использовании константной переменной компилятор проверяет правильность задания константы, и если она будет задана неверно, то будет выдана ошибка именно в операторе, в котором дано определение константной переменной.
Если использована именованная константа, заданная директивой препроцессора #define , то ошибка будет показана только там, где используется константа. Например:
// в директиве препроцессора сделаем ошибку:
t = PI * 2; // в этой строке компилятор выдаст ошибку,
// хотя на самом деле ошибка допущена гораздо раньше!
Как сделать переменную константой c
Отличительной особенностью переменных является то, что мы можем многократно в течение работы программы изменять их значение:
int n ; n = 9; n = 5;
Но кроме переменных в языке программирования C++ можно определять константы . Их значение устанавливается один раз и впоследствии мы его не можем изменить. Константа определяется практически так же, как и переменная за тем исключением, что в начале определения константы идет ключевое слово const . Например:
const int n ; // или // const int n = 22;
И также в процессе программы мы сможем обращаться к значению константы:
#include int main() < const int age ; std::cout
Но если же мы захотим после определения константы присвоить ей некоторое значение, то компилятор не сможет скомпилировать программу и выведет ошибку:
const int age ; age = 78;
То есть такой код не будет работать. И так как нельзя изменить значения константы, то ее всегда необходимо инициализировать, если мы хотим, чтобы она имела некоторое значение.
Если константа не будет инициализирована, то компилятор также выведет ошибку и не сможет скомпилировать программу, как в следующем случае:
const int age;
В качестве значения константам можно передавать как обычные литералы, так и динамически вычисляемые значения, например, значения переменных или других констант:
int a ; const int b ; const int d ; const int x ;
Обычно в качестве констант определяются такие значения, которые должны оставаться постоянными в течение работы всей программы и не могут быть изменены. Например, если программы выполняет математические операции с использованием числа PI, то было бы оптимально определить данное значение как константу, так как оно все равно в принципе неизменно:
C++: Квалификаторы const и constexpr
В этом уроке мы познакомимся с константами и узнаем какие виды констант бывают в С++.
До сих пор все переменные, которые мы видели, были непостоянными, то есть их значения можно изменить в любое время. Однако иногда бывает полезно определять переменные со значениями, которые нельзя изменить. Например, есть математическая постоянная число Пи: 3,14. Маловероятно, что в ближайшее время оно изменится. Определение этого значения как константы помогает гарантировать, что оно не будет случайно изменено.
Чтобы сделать переменную константой, просто поместите ключевое слово const до или после типа переменной, например:
const double kPi < 3.14 >; int const kMonthInYear < 12 >;
Хотя оба варианта считаются валидным, все же стандартами кодирования рекомендуется использовать первый.
При объявлении константы мы сразу же должны инициализировать ее значением, иначе получим ошибку компиляции.
const double kGravity; // ошибка компиляции, должна быть инициализирована при определении
Обратите внимание, что константные переменные могут быть инициализированы из других переменных:
int main() < std::cout ; std::cin >> age; const int kUsersAge < age >; >
Константы времени выполнения и константы времени компиляции
На самом деле C++ имеет два разных типа констант.
Константы времени выполнения – это те, значения инициализации которых могут быть вычислены только во время выполнения, когда ваша программа работает. Такие переменная, как kUsersAge в приведенном выше фрагменте, является константой времени выполнения, поскольку компилятор не может определить ее начальное значение во время компиляции. kUsersAge полагается на ввод данных пользователем (который может быть предоставлен только во время выполнения). Однако после инициализации значение этой константы изменить нельзя.
Константы времени компиляции – это те, чьи значения инициализации могут быть вычислены во время компиляции.
const double kGravity < 9.8 >;
Переменная kGravity выше является примером постоянной времени компиляции. Константы времени компиляции позволяют компилятору выполнять оптимизацию, недоступную для констант времени выполнения. Например, всякий раз, когда используется kGravity , компилятор может просто заменить идентификатор kGravity литералом 9.8 типа double .
Чтобы обеспечить большую конкретность, в C++11 введено ключевое слово constexpr , которое гарантирует, что константа должна быть константой времени компиляции:
int main() < constexpr double kGravity < 9.8 >; // значение 9,8 может быть определено во время компиляции constexpr int kSum < 4 + 5 >; // значение 4 + 5 может быть определено во время компиляции std::cout ; std::cin >> age; constexpr int kMyAge < age >; // ошибка компиляции >
В этом уроке мы познакомились с константами в С++ и узнали что константы бывают двух видов: времени выполнения и времени компиляции.
Задание
Допишите программу, которая принимает в качестве аргумента командной строки радиус, находит длину окружности и выводит ее на экран. Длина окружности вычисляется по формуле: С = 2 * pi * r. Число Пи задайте константой.
Упражнение не проходит проверку — что делать?
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя
Это нормально , в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Константы и глобальные переменные C++
Она является глобальной константой в пределах модуля.
Отслеживать
ответ дан 15 окт 2012 в 20:32
23.9k 2 2 золотых знака 37 37 серебряных знаков 69 69 бронзовых знаков
модуля? В C++ же нет модулей. Или имелся ввиду объектый файл?
15 окт 2012 в 20:54
Они тоже иногда модулями называются. Есно, не в том смысле, как в Питоне или Перле. Просто единица разделения текста и единица компиляции. А объектный файл — продукт их компиляции. Просто одним и тем же термином могут называться несколько разные вещи. Это типа полиморфизм.
15 окт 2012 в 21:12
@mikillskegg, и все таки я не понимаю — почему в пределах модуля? Ведь если положить этот .o (с main) в lib1.so ( gcc -fPIC -shared -o lib1.so main.c ), написать функцию int get_extern_a() < extern int a; return a; >и положить ее в lib2.so, то третий модуль, загрузив эти библиотеки и вызвав «get_extern_a» тоже (наряду с функциями в lib1.so и lib2.so) получит доступ к обсуждаемой переменной. — Так, что IMHO ее надо называть просто глобальной.
15 окт 2012 в 22:14
А напрямую ее получиться получить? Через вызов функции и значения автоматических переменных взять можно.
15 окт 2012 в 22:26
Зона видимости этой константы — все функции в данном модуле. В другом модуле непосредственно она не будет видима. И я не понимаю, что тут еще можно обсуждать.
15 окт 2012 в 22:31
@mikillskegg, к сожалению комментарии закончились. Наверное я не понял Ваш комментарий
Если у переменной или константы не указан модификатор extern/static, то она по умолчанию считается static (кстати, функции, в том числе методы классов, - наоборот). Если переменная определяется без extern, а в других модулях объявляется как extern, то при сборке линковщик будет сильно ругаться, что не может найти переменную.
Особенно в части ругани линковщика, но проверил.
// e1.c #include #include int ext = 999; main () < printf ("main: int ext = %d\n",ext); ext++; e2(); ext++; e3(); printf ("End main: int ext = %d\n",ext); exit (0); >// e2.c #include extern int ext; void e2() < printf ("e2: extern int ext = %d\n",ext); >// e3.c #include extern int ext; void e3()
Вот оттранслировал и запустил
c:/Users/avp/src/cc/hashcode $ gcc -c e1.c e2.c e3.c c:/Users/avp/src/cc/hashcode $ gcc -o e e1.o e2.o e3.o c:/Users/avp/src/cc/hashcode $ ./e main: int ext = 999 e2: extern int ext = 1000 e3: extern int ext = 1001 End main: int ext = 1001 c:/Users/avp/src/cc/hashcode $
Почему-то у меня никто не ругается.
Вот что интересного увидел по поводу extern и const в C++.
Если написать в e1.c
extern const int ext = 12999; int const ext1 = 999;
и транслировать g++ -c e1.c то в выводе nm e1.o увидим, что ext1 локальная константа в секции .rdata, а ext глобальная в той же секции
c:/Users/avp/src/cc/hashcode $ nm e1.o 00000000 b .bss 00000000 d .data 00000000 r .rdata 00000000 t .text U __Z2e2v U ___main U __alloca U _exit 00000000 R _ext 00000030 r _ext1 00000000 T _main U _printf
при такой записи (например в e2.c) (отличается от ext в e1.c присваиванием)
extern const int ext;
g++ -c e2.c делает такой .o модуль
c:/Users/avp/src/cc/hashcode $ nm e2.o 00000000 b .bss 00000000 d .data 00000000 r .rdata 00000000 t .text 00000000 T __Z2e2v U _ext U _printf
т.е. ext здесь глобальная и не определена
Ну, теперь все линкуется, т.к. в модуле a1.o ext определена с флагом R, т.е. глобальная и определена.
Все же удивительное различие семантики слова extern для констант и переменных в С++.
Отслеживать
ответ дан 16 окт 2012 в 17:41
45.8k 6 6 золотых знаков 45 45 серебряных знаков 115 115 бронзовых знаков
ОК. А теперь ближе к вопросу: добавим const и запустим g++
16 окт 2012 в 18:18
Да, кресты с const не хотят (без const, кстати работает) c:/Users/avp/src/cc/hashcode $ g++ -c e1.c e2.c e3.c c:/Users/avp/src/cc/hashcode $ g++ -o e e1.o e2.o e3.o e2.o:e2.c:(.text+0x7): undefined reference to ext’ e3.o:e3.c:(.text+0x7): undefined reference to ext’ collect2: ld returned 1 exit status c:/Users/avp/src/cc/hashcode $ gcc -o e e1.o e2.o e3.o e2.o:e2.c:(.text+0x7): undefined reference to ext’ e3.o:e3.c:(.text+0x7): undefined reference to ext’ collect2: ld returned 1 exit status c:/Users/avp/src/cc/hashcode $ Дурацкий язык
16 окт 2012 в 18:34
Все равно плюсую, потому что относительно переменных я был неправ
16 окт 2012 в 18:50
Можете сказать, модули в первую очередь предназначены для повышения скорости компиляции? 4 модуля скомпилировались. изменяем модуль 3. требуется компилировать только модуль 3, Так как 1,2,4 уже скомпилированны. Или есть еще какие моменты которые следует знать? Там есть какие нибудь шаблоны, которые изначально рассчитаны на модульное проектирование?
16 окт 2012 в 18:52
@mikillskegg, я тоже, как только узнал от Вас про такое с константами в плюсах.
16 окт 2012 в 19:03
@mega, это не свойство того или иного типа исполняемых файлов. Это стандарт языка. А в бинарном виде теоретически это может быть реализовано по-разному.
@mikillskegg, а я и не говорю о свойстве того или иного типа исполняемых файлов. Но здесь пишут об extern , выдавая его за свойство «глобальности» переменных, поэтому я уточнил его истинную функцию, касаемо COFF.
@mega, так будет не только в COFF, но и в других форматах объектного модуля. При такой логике, вообще, глобальная переменная может быть только в пределах модуля, а из других модулей, образующих программу (причем неважно, статически или динамически собранную) могут быть только ссылки на нее.
@avp, что касается констант, Вы наверное и сами вкурсе, что большинство компиляторов сконфигурированных определенным образом, глобальную константу физически даже заводить не будут ни в одном модуле.
Вот, захотелось бы увидеть какую-нибудь глобальную переменную не в пределах модуля. Можете продемонстрировать?
Наверное, Вы имели ввиду глобальную переменную в пределах нескольких модулей? Рискну предположить, что именно технически такой глобальной переменной будет та, что лежит в shared section . У Microsoft это может выглядеть как-нибудь так:
#pragma comment( linker, "/SECTION:.shared,RWS" ) #pragma data_seg( ".shared" ) int a = 0; #pragma data_seg()
Здесь вся секция shared будет присутствовать в единственном экземпляре, независимо от того, сколько экземпляров программы запущено, т.е. a присутствует сразу в нескольких модулях, она глобальна и она «уникальна». Вы это хотели увидеть?