Как реализовать strstr () без отбрасывания const?
strstr
является функцией, соответствующей C99, сигнатура типа которой является следующей:
char *strstr(const char *haystack, const char *needle);
можно реализовать эту функцию не отбрасывая const
куда-то?
Для справки -реализация Apple, а вот реализация GNU. Оба отбросили const
в конце.
2 ответов
вы не можете реализовать strstr()
без нарушения const
как-то правильности. Гипс-самый простой способ сделать это. Вероятно, вы можете как-то скрыть нарушение (например, вы можете использовать memcpy()
скопировать значение указателя), но нет смысла делать это.
проблема в том, что strstr()
принимает const char*
, что указывает на строку, и возвращаетconst
char*
это указывает на ту же строку.
например, это программа:
#include <stdio.h>
#include <string.h>
int main(void) {
const char s[] = "hello";
char *result = strstr(s, "hello");
*result = 'H';
puts(result);
}
изменяет (или, по крайней мере, пытается изменить) a const
-квалифицированный объект, без использования указателя или любой другой явно небезопасной конструкции.
еще в 1989 году комитет ANSI C мог бы избежали этой проблемы, определив две разные функции, скажем:
const char *strcstr(const char *haystack, const char *needle);
char *strstr ( char *haystack, const char *needle);
тот, который возвращает указатель на const char
дали const
аргументы, а другой, который возвращает указатель на изменяемый char
дали модифицируемый аргумент. (C++, который наследует стандартную библиотеку C, делает это путем перегрузки.)
strstr()
один из нескольких стандартных строковых функций, которые имеют эту проблему.
что вы видите в случае strstr
(и некоторые другие стандартные функции) - это идиоматическое решение, целью которых является поддержка немодифицируемые операций как const и не const строки один.
Да, для реализации такой функции необходимо явно отбросить константу от входного указателя. Обратите внимание, что приведение само по себе еще ничего физически не нарушает (это означает: оно не пытается изменить постоянные данные и не вызывает неопределенное поведение). Тем не менее, он открывает дверь для таких нарушений, возвращая неконст-указатель на данные const вызывающему объекту, т. е. нарушает концептуальные правила const-корректности.
альтернативным решением было бы предоставить две версии одной и той же стандартной функции - const и non-const - но без перегрузки функции в стиле C++это потребует двух отличительных имен функций, что не обязательно выглядит как очень хорошая идея (и даже при перегрузке функции в стиле C++у нее тоже есть свои проблемы).
в этом случае это фактически ответственность вызывающего абонента получить результат в указатель того же типа, что и тот, который был передан в качестве аргумента. Если указатель аргумента был const-квалифицирован, очень хорошая практика программирования-получить результат в указатель, который также является const-квалифицированным. Пока это руководство соблюдается, эта идиома действительно чувствует себя как дома в области C язык.