#c #c99
#c #c99
Вопрос:
Я не занимался C или C уже более десяти лет, и я работаю над небольшим проектом, чтобы снова освоиться с ним, и пытаюсь определить хорошие и плохие привычки, где я могу. Одна вещь, с которой я столкнулся, это const
аргументы, которые не только должны быть сигналом для потребителей о том, что значения не изменятся. Я большой поклонник сигналов неизменности, поэтому я подумал, что это было бы здорово.
Пока я не начал играть с этим и не написал следующий код:
#include <stdio.h>
#include <stdlib.h>
struct A {
int value;
};
struct B {
struct A* a;
};
void DoStuff(const struct B* b) {
b->a->value = 5;
}
int main() {
struct B* b = malloc(sizeof(struct B));
b->a = malloc(sizeof(struct A));
DoStuff(b);
printf("Value: %in", b->a->value);
}
К моему большому удивлению, когда я скомпилировал via gcc -Wall -Wextra -std=c99 test.c -o test.exe
, я не получил никаких предупреждений, ошибок или чего-либо еще, и все работало так, как ожидалось.
Итак, что const
должно сигнализировать? Я не уверен, что считаю правильным указывать const там, где это позволяет компилятор, потому что, если я использую его в подобных ситуациях, потребители могут не ожидать изменения внутренних значений, и я беспокоюсь о том, чтобы использовать функции, которые являются чистыми прямо сейчас, но я добавляю побочные эффекты позже, не забывая удалять const
.
Ответ №1:
const
Защищает элементы самого struct B
себя. Таким образом, вы не можете переназначить указатель, хранящийся в a
, но поскольку этот указатель не указывает на a const struct A
, вы все равно можете изменять члены структуры, на которую он указывает.
Ответ №2:
Итак, что
const
должно сигнализировать?
При void DoStuff(const struct B* b)
этом данные b
, на которые указывают, не должны быть изменены. При b->a->value = 5;
этом данные b
, на которые указывают, не меняются. b->a
остается неизменным.
value
изменения, но это не данные, на которые указывает a
.
Хорошие компиляторы предупреждают, когда код пытается напрямую изменить const
данные.
Изменение помеченных данных const
в отдельных случаях допустимо.
Было бы нормально, если бы код изменился b->a
так, (struct B*)b->a = 0
как struct B* b
если бы изначально была назначена точка, не являющаяся const
данными. Если бы данные b
указывали на been const
, то (struct B*)b->a = 0
это было бы неопределенное поведение (UB).