Если два указателя (lvalue доступы) могут псевдоним , это другой вопрос, чем если бы они указывали на совместимые типы . Часть, которую вы цитируете, касается псевдонимов указателей (иначе говоря, «строгое правило псевдонимов»), которая по какой-то причине записывается как:
- тип, совместимый с эффективным типом объекта,
- квалифицированная версия типа, совместимого с эффективным типом объекта
Это означает, что объект с квалификацией const может псевдоним не квалифицированным объектом, даже если они не являются совместимыми типами. Пример:
void f (const int* a, int* b);
a
может указывать на те же данные, что и b
. Компилятор не вправе предполагать, что они указывают на отдельные объекты.
Но это даже не относится к вашему случаю, поскольку вы передаете параметр по значению и создаете локальную копию. Псевдоним будет применяться, если ваш пример был такой:
double a = 10.2;
int main(int args, const char *argv[]){
print_double(&a);
}
void print_double(const double* b){
printf("d = %lf\n", b);
}
Где параметр b
- это квалифицированная версия типа, совместимого с эффективным типом объекта (double
). Поэтому компилятор может не предполагать, что b
не указывает на глобальную переменную a
.
По поводу совместимости:
Всякий раз, когда вы копируете объект либо с помощью присваивания =
, либо путем передачи его в качестве параметра функции, правила простого присвоения включаются. 6.5.16.1 позволяет это:
- левый операнд имеет атомарный, квалифицированный или неквалифицированный тип указателя и (учитывая
тип, который левый операнд будет иметь после преобразования lvalue) оба операнда
указатели на квалифицированные или неквалифицированные версии совместимых типов, а тип указывает
слева находятся все квалификаторы того типа, на который указывает справа;
Значение int* a; const int* b = a;
в порядке, но const int* a; int* b = a;
является нарушением ограничения. При передаче параметров применяются те же правила, см. 6.9.1 / 10:
При входе в функцию выражения размера каждого изменяемого параметра
оценивается, и значение каждого выражения аргумента преобразуется в тип
соответствующий параметр как бы по присваиванию.
В вашем случае происходит то, что значение d
в вызывающей стороне копируется в новую переменную типа const double
. Это разрешено по правилу простого присваивания, и вы создаете новую переменную - все хорошо.