Является ли подпись char проблемой интерфейса?
Предположим, у меня есть функция
void foo(char *)
который внутренне должен обрабатывать свой ввод как блок байтов с NUL-символами (скажем, это хеш-функция для строк). Я мог бы привести аргумент unsigned char*
в функции. Я также мог бы изменить объявление на
void foo(unsigned char *)
Теперь, учитывая, что char
, signed char
а также unsigned char
три разных типа, будет ли это представлять собой изменение интерфейса при любом разумном определении термина "интерфейс" в C?
(Этот вопрос предназначен для урегулирования дискуссии, возникшей в связи с другим вопросом. У меня есть свое мнение, но я не приму ответ, пока один не станет победителем по итогам голосования других.)
5 ответов
Согласно ISO/IEC 9899:TC3,
- вызов функции через выражение несовместимого типа - неопределенное поведение (6.5.2.2 §9)
- совместимые типы функций должны иметь совместимые типы параметров (6.7.5.3 §15)
- совместимые типы указателей должны указывать на совместимые типы (6.7.5.1 §2)
char
,signed char
а такжеunsigned char
разные базовые типы (6.2.5 §14) и, следовательно, несовместимы (6.2.7 §1), что также явно упоминается в сноске 35 на стр. 35
Так что да, это явно изменение интерфейса программирования.
Тем не менее, как char *
, signed char *
а также unsigned char *
будет иметь идентичные представления и требования выравнивания в любой разумной реализации языка C, двоичный интерфейс останется неизменным.
Да, это. Клиентский код, который был ранее скомпилирован, больше не будет компилироваться (или, в любом случае, может генерировать новые предупреждения), поэтому это серьезное изменение.
Я выбираю "С - ничего из вышеперечисленного".
Хотя это и не прямой ответ на вопрос, который вы на самом деле задали, правильное решение ситуации кажется мне довольно простым и очевидным: вам не следует использовать ничего из вышеперечисленного.
По крайней мере, IMO, у вас есть действительно веская причина поступить иначе, ваша функция должна принять void *
или (предпочтительно) void const *
, То, что вы ищете, в основном непрозрачный указатель, и это именно то, что void *
обеспечивает. Пользователю не нужно ничего знать о внутренностях вашей реализации, и поскольку любой другой тип указателя преобразуется в void *
неявно, это одна из немногих возможностей, которая также не нарушает существующий код.
Нет, это не так. Любые изменения в клиентском коде тривиальны (особенно если это просто для того, чтобы избежать предупреждения), и на практике практически во всех реализациях C вы обнаружите, что вам даже не нужна повторная компиляция, потому что указатели на char*
а также unsigned char*
будет передан точно так же в соглашении о вызовах.
Преобразует ли символ * неявно в символ * без знака?
- Да - вы не сломали свой интерфейс
- Нет - вы слили реализацию
подробности.