Добавление квалификатора к указанному типу является неявным преобразованием, тогда как удаление квалификатора требует явного приведения.
Прототип bsearch()
написан таким образом, что допускает оба следующих использования без явного приведения:
int needle = 0xdeadbeef;
int foo[42] = { ... };
int *p = bsearch(&needle, foo, 42, sizeof *foo, cmpi);
const int bar[42] = { ... };
const int *q = bsearch(&needle, bar, 42, sizeof *bar, cmpi);
Однако это означает, что можно использовать bsearch()
- как и многие другие функции libc - для удаления const-квалификации без предупреждения, например, если мы написали
int *q = bsearch(&needle, bar, 42, sizeof *bar, cmpi);
Это совершенно законно: неопределенное поведение возникает, только если мы действительно использовали q
для изменения bar
.
Вам также следует помнить, что квалифицированный const параметр указателя влияет только на то, какие аргументы принимаются без приведения, но не гарантирует, что функция не изменит указанный объект . Это просто соглашение, за которым следует практически весь существующий код, но оно не обеспечивается семантикой языка.
В частности, компиляторы не могут использовать эту информацию для оптимизации в вызывающем коде - компилятор должен видеть тело функции, потому что законно удалить квалификацию const из указателя и изменить объект-указатель, если объект сам не был объявлен const
.
В прошлом я предполагал, что дополнительная ограничивающая квалификация аргумента указателя будет обеспечивать неизменность, но тщательное перечитывание раздела 6.7.3.1 приводит меня к мысли, что это не так: ограничения, налагаемые на указанные объекты указатели с ограниченным ограничением вступают в силу, только если указатель фактически используется для доступа к объекту, но вызывающий код не может сделать это предположение только из прототипа ...