Преимущества strncmp перед strcmp?

Кажется strncmp обычно рекомендуется чем strcmp, Каковы преимущества? Я думаю, что это может быть связано с безопасностью. Если это так, то все еще применимо, если известно, что одна из входных строк является литеральной константой, например "LiteralString"?

ОБНОВЛЕНИЕ: я имею в виду при том же сценарии пользователя, где нужно сравнивать целые строки, и strncmp можно использовать как показано ниже. Мне интересно, имеет ли это смысл или нет.

strncmp(inputString, "LiternalString", strlen("LiternalString"));

8 ответов

Проблема с strcmp в том, что иногда, если по ошибке передаваемые аргументы не являются допустимыми C-строками (это означает, что p1 или p2 не заканчиваются нулевым символом, то есть не завершается строкой NULL), тогда strcmp продолжает сравнение, пока не достигнет недоступности память и сбои или иногда приводит к неожиданному поведению.

С помощью strncmp Вы можете ограничить поиск, чтобы он не достигал недоступной памяти.

Но из этого не следует говорить, что strcmp небезопасно Обе функции хорошо работают так, как они предназначены для работы. Программист должен прочитать man страница для этой функции перед ее использованием и должна быть достаточно искренней при передаче параметров в такие библиотечные функции.

Вы также можете прочитать ЭТО, в котором содержится почти аналогичный вопрос.

strncmp не имеет "преимуществ перед strcmp"; скорее они решают разные проблемы. strcmp предназначен для определения, равны ли две строки (и, если нет, возможно, как упорядочить / отсортировать их по отношению друг к другу). strncmp (главным образом) для определения, начинается ли строка с определенного префикса. Например:

if (strncmp(str, "--option=", 9)==0)

будет определять, если str начинается с "--option=", Это не может быть достигнуто путем strcmp без изменения проверяемой строки (которая может быть недопустимой операцией) или создания ее бесполезной копии. Это также не может быть достигнуто с memcmp если вы уже не знаете str указывает на объект длиной не менее 9 байт; в противном случае вызов memcmp будет иметь неопределенное поведение.

Есть и другие варианты использования strncmp также, например, работа с данными не-C-строки.

Все зависит от ваших сценариев использования. использование strncmp если вам нужно сравнить только фиксированное количество символов, используйте strcmp если вам нужно сравнить всю строку.

Вот и все.

... в том же пользовательском сценарии, когда нужно сравнивать целые строки,...

 strncmp(inputString, "LiternalString", strlen("LiternalString"));

Рассмотрим случай, когда строка inputStringдлиннее строкового литерала.

const char *inputString = "LiternalString_XYZ";
int cmp = strncmp(inputString, "LiternalString", strlen("LiternalString"));
printf("%d\n", cmp); // prints 0.

Но OP хотел сравнить целые строки.

const char *inputString = "LiternalString_XYZ";
int cmp = strcmp(inputString, "LiternalString");
printf("%d\n", cmp); // prints non-zero.

Заключение на прямой вопрос OP

Мне интересно это имеет смысл или нет.

Нет. Чтобы сравнить строки целиком,strncmp()не всегда обеспечивает правильный результат. Использоватьstrcmp().


В дальнейшем

strncmp(s1,s2,n)может ограничить поиск, чтобы он не доходил до недоступной памяти, если n был правильно вычислен - что не было сделано в коде OP и проблематично сделать правильно, когда n отличается для s1 а также s2.

Ограничение размера n относится к обоим s1 а также s2 что делает эту функцию полезной для сравнения префиксов, но не "более безопасной".

В случае OP нет причин ограничивать поиск из-за "безопасности" из-за длины строки строкового литерала, поскольку строковые литералы всегда содержат завершающий нулевой символ.

Если что-то, n должно было основываться на каком-то свойстве inputString.

Код вроде strncmp(s1, string_literal, strlen(s1))является функционально неверным, так как при сравнении отсутствует нулевой символ. Немного лучшеstrncmp(s1, string_literal, strlen(s1)+1), но функционально это то же самое, что и более простой strcmp(s1, string_literal) без снижения "безопасности".


Приведенные ниже предложения улучшают "безопасность" на случай, если foo()неправильно сформировали строки, но могут дать неправильный ответ, еслиN != M как указано выше.

char s1[N];
foo(s1); // populate s1 somehow
int cmp = strncmp(s1, string_literal, sizeof s1);

char s1[N];
char s2[M];
foo(s1); // populate s1 somehow
foo(s2); // populate s2 somehow
int cmp = strncmp(s1, s2, min(sizeof s1, sizeof s2));

Но в этих случаях проблема заключается в foo(), не здесь.
Для меня, еслиfoo() было настолько сомнительно, что я бы использовал следующие

s1[sizeof s1 - 1] = '\0';
s2[sizeof s2 - 1] = '\0';
int cmp = strcmp(s1, s2);

или обнаружить это foo()не образовывала строку.

char s1[N];
foo(s1);
if (memchr(s1, '\0', sizeof s1) == NULL) Oops();

Мораль истории: strncmp() не является "более безопасной" версией strcmp(). Это инструмент для другой работы: сравнения строковых префиксов.

Просто опубликуйте пример использования анти-strncmp здесь. Подумайте о следующем коде.

#include <stdio.h>
#include <dirent.h>

int main()
{
    //I want to list all files under current folder, include hidden files.
    DIR *dir;
    struct dirent *dp;
    char * file_name;
    dir = opendir(".");
    while ((dp=readdir(dir)) != NULL) {
        printf("debug: %s\n", dp->d_name);
        if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") )
        //It doesn't work if you replace strcmp with strncmp here.
        //if ( !strncmp(dp->d_name, ".", 1) || !strncmp(dp->d_name, "..", 2) )  
        {
        } else {
            file_name = dp->d_name;
            printf("file_name: \"%s\"\n",file_name);
        }
    }
    closedir(dir);
    return 0;
}
int ret1, ret2;
char dev1[]  = { "ABC" };
char dev2[4] = { "ABC" };

dev2[3] = 'D';
ret1 = strncmp(dev1,dev2,strlen(dev1));  // # of characters
ret2 = strncmp(dev1,dev2,sizeof(dev1));  // # of characters plus '\0'

Предположим: dev1 имеет нулевое значение, а dev2, вероятно, нет. ret1 = 0 (ложноположительный результат), а не ret2=-1 (действительный результат)

fazit: strncmp - не просто безопасный способ для strcmp. зависит от того, как вы используете это.

я бы использовал strcmp для строк и strncmp для поиска подстрок.

strcmp может привести к ошибке заполнения и сегментации памяти в случае, если один из аргументов не является строкой с нулевым символом в конце. Посмотрите, почему вы должны использовать strncpy вместо strcpy. Последствия вряд ли произойдут в strcmp, но проблема та же. Семейство функций strnxxx пытается предотвратить чтение / запись не полученной памяти.

Недостатком использования strn является дополнительная операция сравнения и уменьшения на счетчике.

В двух словах: strncmp безопаснее, чем strcmp, но и медленнее.

Я мог видеть только одно преимущество: strncmp будет выполняться немного меньше времени, чем strcmp, поскольку мы всегда будем сравнивать префикс строки с comapre, а не всю строку.

Я не думаю, что в алгоритме strcmp и strncmp есть какой-то аспект безопасности. Они одинаковы за исключением того, что в strncmp сравниваются только первые символы 'n'.

strncmp более безопасен, чем strcmp

так же, как strncpy и strcpy или strlen и strnlen, потому что strcmp сравнивает, пока не будет найден первый определитель нуля. strncmp сравнивает до первого нулевого определителя, но не более n символов. Поэтому, если ваша строка имеет определенную длину, лучше использовать strn*-функции.

Смотрите также

http://www.cplusplus.com/reference/cstring/strncmp/?kw=strncmp

Другие вопросы по тегам