Форум программистов, компьютерный форум, киберфорум
Evg
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  

Квалификатор const

Запись от Evg размещена 15.02.2012 в 12:56
Показов 24984 Комментарии 0
Метки c, c++, си

ВНИМАНИЕ! Вопросы по существу обсуждаемого вопроса просьба задавать здесь или создать тему на форуме и кинуть на неё ссылку в блог или мне в личку.
Объясняю почему

Причин для этого несколько.

Я, как и любой другой автор, всегда могу упустить интересный момент обсуждаемой темы (что подтвердилось на практике). А потому задаваемый вопрос может закрывать пробел в статье. Ответ на конкретный вопрос, как правило, дать несложно. Сложнее его аккуратно сформулировать так, чтобы ответ являлся законченной частью статьи. Поэтому, как правило, на первых порах я ограничиваюсь конкретным ответом на конкретный вопрос, а в статью временно вставляю ссылку на пост, где был дан ответ. А когда дойдут руки, то вместо ссылки пишу нормальное пояснение. Технические возможности блога не позволяют в комментариях пользоваться широкими возможностями, доступными на форуме (то как выделение текста жирным, вставка фрагментов исходников в удобном для чтения виде и т.п.), поэтому будет удобнее, если вопрос и ответ будут опубликованы на форуме

Любая статья является изложением знаний в общем случае. У многих людей мышление устроено так, что прочтя на форуме конкретный вопрос и конкретный ответ на этот вопрос, у них появится бОльшее понимание, чем после прочтения теоретических выкладок (даже если они подкреплены конкретными примерами). Ссылки на такие обсуждения я, как правило, включаю в последний раздел статьи.

Начинающие, как правило, поиск ответов на свои вопросы ведут именно в форуме, а не в блогах. А потому конкретный вопрос и конкретный ответ для них будет более удобным и полезным именно на форуме. Многие люди умеют работать методом тыка, лишь бы был конкретный пример в качестве образца. А потому такое обсуждение будет им полезным даже без прочтения статьи

Исторически сложилось, что раньше (когда ещё не было блога) статьи располагались на форуме и представлены были в виде двух тем. Первая тема создавалась в специально отведённой свалке и представляла собой черновик, который со временем дорабатывался до законченной статьи. После этого статья переезжала во вторую тему в тематическом разделе. А первая тема оставалась дополнительной свалкой для замечаний и мелких вопросов по теме. Ссылку на старое местоположение данной свалки я помещаю в начале статьи. Вопросы, по возможности, прошу создавать в отдельных темах, но если вопрос действительно мелкий, то можно его задать и в указанной свалке.





1. Общие сведения

Неформальное объяснение действия квалификатора const состоит в том, что квалификатор действует на тип-указатель (а точнее, на звёздочку) или переменную, которые написаны справа от квалификатора.

2. Переменная, которую нельзя модифицировать

C
1
int const a;
Справа от const находится переменная. Означает, что константной является переменная, т.е. в неё записывать нельзя. Однако формально с точки зрения языка мы имеем переменную "a" с типом "const int" (а не константную переменную "a" с типом "int"). Это означает, что для конструкции

C
1
int *b = &a;
компилятор выругается на неявное преобразование, поскольку переменная b имеет тип "указатель на int", а выражение "&a" имеет тип "указатель на const int". По умолчанию такое преобразование считается опасным, т.к. по языку через "b" можно будет сделать запись в "a". Поэтому компилятор пропустит такой код только с явным преобразованием

C
1
int *b = (int*) &a;
а после любого явного преобразования указателей компилятор снимает с себя всякую ответственность за неправильный код типа

C
1
2
3
4
5
6
7
8
const int a = 5;
int *b = (int*) &a;
...
/* Здесь мы изменили значение переменной a, которую описали с квалификатором
 * const. В случае работы с оптимизациями компилятор может нижеидущий
 * код "x=a" заменить на "x=5", поскольку "a" описано как немодифицируемая переменная */
*b = 6;
int x = a;
Ну и следует упомянуть, что зачастую пишут

C
1
const int a;
что является эквивалентной записью, поскольку, как я уже говорил, неформально квалификатор const действует ТОЛЬКО на типы-указатели и переменные. Т.е. const по сути действует на "a", поскольку "int" не является типом-указателем

3. Указатель, по которому нельзя модифицировать

C
1
int const *c;
или, как чаще пишут

C
1
const int *c;
В данном случае const действует на тип-указатель "int*" (т.е. const действует на звёздочку, которая относится к int). В итоге мы имеем переменную "c", которая имеет тип "const int*", что есть "указатель на const int". Конструкция означает, что мы имеем указатель, по которому нельзя ничего модифицировать и который указывает на немодифицируемую память

При этом с указателями const есть некий тонкий момент. Программист обязан сам следить за тем, чтобы во время жизни переменной с типом "указатель на const" он всегда смотрел на немодифицируемые участки памяти. С точки зрения синтаксиса следующий код является коректным

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const int *c;
int d;
 
/* На такую конструкцию компилятор НЕ должен ругаться, т.к.
 * с точки зрения поинтерных записей конструкция опасной не является,
 * т.е. через указатель "c" мы не можем модифицировать
 * значение переменной "d" */
c = &d;
...
int x = *c;
...
/* В этом месте код формально становится некорректным, т.к. компилятор
 * в режиме с оптимизациями имеет право нижеидущий код "y=*c"
 * заменить на "y=x", поскольку "c" должно указывать на неизменяемую
 * память */
d++;
...
int y = *c;
но на исполнении в теории может повести себя не так, как ожидалось (зависит от компилятора)

4. Будьте внимательны при описании указателя на const

Как уже говорилось выше, неформально квалификатор const влияет на звёздочку или на имя переменной, стоящей справа от квалификатора. Очередная расхлябанность языка Си приводит к тому, что записи

C
1
int const a;
и

C
1
const int a;
являются эквивалентными. Во втором случае справа от const находится тип "int", на который const НЕ влияет (поскольку он влияет только на звёздочки и имена переменных), а потому const как бы относится только к имени переменной "a". Однако я предпочитаю первую форму записи. И вот почему. При работе с const нужно учитывать, что квалификатор влияет только на явные звёздочки. В записи

C
1
2
typedef int* ptr_t;
const ptr_t a;
квалификатор const относится к переменной "a", поскольку справа от const'а нет явных звёздочек. Однако если мы раскроем typedef текстовой заменой "ptr_t" на "int*", то мы получим неэквивалентную запись

C
1
const int* a;
поскольку const уже относится к указателю, а не переменной. Именно по этой причине я пишу "int const a;", а не "const int a;"

5. Краткие итоги

Чтобы итог всего этого дела был перед глазами, напишу всё в одном месте:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Переменную нельзя модифицировать */
int const a;
 
/* Эквивалентно "int const a;" */
const int a;
 
/* Указатель модифицировать (a = ...) можно, но записывать
 * по указателю (*a = ...) нельзя */
const int *a;
 
/* Эквивалентно "const int *a;" */
int const *a;
 
/* Указатель модифицировать (a = ...) нельзя, но записывать
 * по указателю (*a = ...) можно */
int * const a;
 
/* Указатель модифицировать (a = ...) нельзя, записывать
 * по указателю (*a = ...) нельзя */
const int * const a;
Для полноты картины следует написать, что для ссылок в Си++ (не путать с указателями) квалификатор const работает по тому же принципу: действует на "&", находящийся справа от квалификатора. В случае ссылки прилеплять квалификатор к имени переменной смысла не имеет, потому как по языку ссылки и так нельзя модифицировать. Опять-таки для полноты картины: для квалификатора volatile работают все те же правила, что и для квалификатора const.

Вкратце можно сказать про три основных назначения квалификатора const:
  • Уберечь от собственных ошибок на этапе компиляции. Понятно, что на этапе текстового разбора могут выявиться только ошибки, где идёт запись напрямую через переменную с квалификатором const (или типа которой есть указатель на const). Если же имеют место быть случаи типа того, что приведён в разделе 4.3, то тут уже ничто от ошибки не спасёт
  • При передаче параметров в функции. Очень часто требуется в функцию передать аггрегатный (структура или массив, коим в том числе являются и строки Си) параметр. В случае, когда параметр в функции только читается, то можно поступить двумя способами. Передать по значению или передать по косвенности через const-указатель (или const-ссылку в Си++). В первом случае имеется неоптимальность работы кода, т.к. будет копироваться объект большого размера. Во втором случае код будет более быстрый, потому что будет передаваться только адрес объекта, но квалификатор const возле параметра-указателя подскажет программисту о том, что внутри функции записи в объект не произойдёт. Здесь надо сделать оговорку, что внутри функции программист кривыми руками может написать код типа того, что приведено в конце раздела 4.3. В случае работы с массивом в языках Си\Си++ вообще нет никакой возможности передавать их по значению, а потому там работа идёт только по косвенности
  • Оптимизация кода компилятором. Особенно это касается случаев, когда указатель на объект передаётся в функцию, но в случае параметра в виде const-указателя компилятор понимает, что внутри функции объект не меняется. Однако в реальной жизни оказалось так, что программисты слишком часто пишут неправильные коды (по типу того, что приведён в разделе 4.3), поэтому многие современные компиляторы по умолчанию НЕ делают никаких оптимизаций, связанных с указателями на const, а делают только по специальным опциям типа "доверять квалификаторам const". Либо делают оптимизации, но имеют опцию "НЕ доверять квалификаторам const". Как правило это требуется для сборки старого софта, который писался во времена, когда машины были слабыми, памяти мало, а потому в компиляторах агрессивных оптимизаций не проводилось и такие ошибки не вскрывались

6. Ссылки на темы, где обсуждался данный вопрос
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Асинхронный приём данных из COM-порта
Argus19 01.05.2026
Асинхронный приём данных из COM-порта Купил на aliexpress термопринтер QR701. Он оказался странным. Поключил к Arduino Nano. Был очень удивлён. Наотрез отказывается печатать русские буквы. Чтобы. . .
попытка написать игровой сервер на C++
pyirrlicht 29.04.2026
попытка написать игровой сервер на плюсах с открытым бесконечным миром. возможно получится прикрутить интерпретатор питон для кастомизации игровой логики. что есть на текущий момент:. . .
Контроль уникальности выбранного документа-основания при изменении реквизита
Maks 28.04.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРемонтСпецтехники", разработанного в КА2. Задача: уведомлять пользователя, если указанная заявка (документ-основание). . .
Благородство как наказание
Maks 24.04.2026
У хорошего человека отношения с женщинами всегда складываются трудно. А я человек хороший. Заявляю без тени смущения, потому что гордиться тут нечем. От хорошего человека ждут соответствующего. . .
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
Памятка для бота и "визитка" для читателей "Semantic Universe Layer (Слой семантической вселенной)"
Hrethgir 19.04.2026
Сгенерировано для краткого описания по случаю сборки и компиляции скелета серверного приложения. И пусть после этого скажут, что статьи сгенерированные AI - туфта и не интересно. И это не реклама -. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru