В VB константа — это
особый тип языковой сущности. Есть переменные, а есть константы — и это совершенно разные вещи. В VB это способ некоторое значение пометить именем, чтобы везде в дальнейшем использовать имя вместо самого значения.
В C констант таких как в VB нет вообще. Наиболее близкой к VB заменой являются макроподстановки препроцессора (с помощью #define), но препроцессинг не имеет отношения к самому языку, это просто обработка текста без вникания в его смысл.
А
const является просто квалификатором типа выражения/переменной, которое запрещает (на уровне компилятора) присваивать значение переменной, но переменная остаётся
переменной. Особенно стоит подумать о сочетании квалификаторов
const и
volatile, обозначающее, что переменную не может менять данный код, но она может быть в любой момент изменена каким-то сторонним кодом.
Поэтому, во-первых, модификатор
const может участвовать в аргументах (чего в VB и близко нет) функций.
Поэтому, во-вторых, возможны вещи вроде:
- const int * a (указатель на int, значение которого нельзя менять),
- int * const a (указатель, значение которого нельзя менять, на int, значение которого менять можно) и
- const int * const a (указатель, значение которого нельзя менять, на int, значение которого нельзя менять).
Есть несколько следствий такого положения дел:
- В VB константа не является переменной, поэтому ей даже нельзя попытаться присвоить новое значение: это будет синтаксические неверно. В Си же константа является просто read-only-для-кода переменной. Ей не получится просто так присвоить значение, но уже не из-за синтаксической неверности, а из-за несоответствия типа. Можно снять с переменной const-квалификатор и спокойно присвоить значение. Но в некоторых случаях это вызовет runtime ошибку.
- Поскольку в Си константа является переменной (хоть и read-only), она занимает своё законное место секции данных или в стековом фрейме процедуры. Применение к ней оператор & (оператора увеличения уровня индирекции) будет всегда давать идентичное значение указателя.
В VB константы не являются переменными, поэтому в стеке оказаться не могут принципиально никак, а объявление внутри процедуры просто делает идентификатор констаниты процедуро-локальным. Глобальные и локальные константы не помещаются в секцию данных (кроме значений строковых констант). Поэтому у константы нет определённого «адреса». Значение числовых констант вшиваются прямо в код (прямо в инструкции). Если нужно передать константу как значение ByRef-аргумента, всё делается так же, как с Implicit-константами: на стеке создаётся временная копия константы и в качестве реального значения ByRef-аргумента передаётся адрес этой копии. Поэтому, внутри процедуры, имеющей ByRef-параметр, можно попытаться изменить значение переданной by reference константы. Изменится, правда, при этом значение временной копии константы, лежащей на стеке. В Си, если константы локальная (внутрипроцедурная), если снять с неё const-квалификатор и проделать аналогичный трюк с функцией-ченджером, значение константы константной переменной изменится! А применение оператор & к Implicit-константе не допускается языком: никакой копии значения на стеке ради того, чтобы оператору & было какой адрес вернуть, создаваться не будет.
.
Оговорка: большинство компиляторов С/С++ для переменных с
const-квалификатором, но без
volatile-квалификатора генерируют такой код, словно это не переменные, а VB-style-константы. Но это оптимизация, а не свойства сущностей в языке. То есть, почему это не имеет прямого отношения к
const — потому что компилятор сделает такую оптимизацию даже если не снабдить переменную
const-квалификатором.