Как реализовать 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 язык.