Загадка с выводом strcmp. Как strcmp на самом деле сравнивает строки?

Я хочу знать, почему strcmp() возвращает разные значения, если используется более одного раза в одной и той же функции. Ниже представлена ​​программа. В первом случае я знаю, почему он печатает -6. Но во втором случае, почему печатается -1?

#include<stdio.h>
#include<string.h>
int main()
{
    char a[10] = "aa";
    char b[10] = "ag";
    printf("%d\n",strcmp(a, b));
    printf("%d\n",strcmp("aa","ag"));
    return 0;
}

И результат, который он производит, ниже

[sxxxx@bhlingxxx test]$ gcc -Wall t51.c
[sxxxx@bhlingxxx test]$ ./a.out
    -6
    -1

Почему выход второй strcmp() -1? Здесь играет Компилятор? Если да, то какую именно оптимизацию он делает?


person Subash Rajaram    schedule 15.02.2019    source источник
comment
Взгляните на сгенерированный машинный код, чтобы увидеть, что он на самом деле делает, и как компилятор транслировал ваш исходный код.   -  person Some programmer dude    schedule 15.02.2019
comment
Вам не нужно заботиться о точном значении, которое он возвращает (если только оно не равно 0); только если он меньше, равен или больше 0.   -  person Shawn    schedule 15.02.2019
comment
Возможно, компилятор при сравнении двух константных строк знает, что ответ отрицательный, и возвращает -1.   -  person Rishikesh Raje    schedule 15.02.2019
comment
Если вы назначите эти литералы указателям (а НЕ массивам символов), результат будет таким же, как и в случае массивов символов, т.е. char* c="aa", *d = "ag"; даст тот же -6.   -  person Duck Dodgers    schedule 15.02.2019
comment
В Clang код OP дает вывод -6 -6. Только в GCC он возвращает -6 -1.   -  person Duck Dodgers    schedule 15.02.2019
comment
@Shawn: Тот факт, что стандарт C указывает только знак результата, не означает, что вам не следует заботиться о величине. Соблюдение стандарта C — это небольшая часть разработки программного обеспечения, а любопытство — отличная мотивация, которая помогает в изучении работы компиляторов, более глубоком понимании семантики и многом другом. Хорошо и ценно заботиться и спрашивать, поскольку полученные знания могут привести к написанию кода, который лучше оптимизируется, с меньшей вероятностью будет содержать ошибки и т. д. Знания ценны, и люди должны заботиться о них.   -  person Eric Postpischil    schedule 15.02.2019
comment
@bruno, я понятия не имею, почему strcmp() при передаче литеральных строк в качестве параметров возвращает -1, только для компилятора gcc. Во всех остальных случаях, char* или массив символов или использование clang, он всегда возвращает -6. Я могу только сказать, что это кажется реализацией. Я просто проверял и констатировал очевидное. :).   -  person Duck Dodgers    schedule 15.02.2019
comment
@JoeyMallone Я плохо читал, на самом деле только один из strcmp вычисляется во время компиляции, а другой во время выполнения, имеет значение только знак / 0, а не значение само по себе (-1 или -6)   -  person bruno    schedule 15.02.2019
comment
@бруно, спасибо. Вы меня немного запутали :D. Я снова и снова просматривал свои комментарии. Да, кажется, что единственная разница - это проверка во время выполнения и во время компиляции. Я думаю, поскольку компилятор уже знает, он останавливается раньше во время сравнения во время компиляции.   -  person Duck Dodgers    schedule 15.02.2019
comment
@JoeyMallone Мне холодно, и мой бедный мозг не получает достаточно кислорода, извините ^^   -  person bruno    schedule 15.02.2019
comment
@бруно, вот там. Скоро лето. Всего на пару недель больше. :)   -  person Duck Dodgers    schedule 15.02.2019
comment
@EricPostpischil, однако, существует опасность того, что любопытство к тому, как именно работает ваша система, может привести к изучению и использованию мелких деталей, которые на самом деле характерны только для вашей системы и которые не дают таких же результатов в других системах. Я думаю, что важно то, что согласно стандарту должно происходить. Пока вы это знаете, вы можете сколько угодно исследовать, как различные системы реализуют это, но если вы этого не сделаете, вы потенциально окажетесь на неправильной стороне неопределенного поведения.   -  person Tim Randall    schedule 15.02.2019


Ответы (3)


В стандарте C говорится следующее о возврате значение strcmp:

Раздел 7.24.4.2p3:

Функция strcmp возвращает целое число, большее, равное или меньшее нуля, соответственно, поскольку строка, на которую указывает s1, больше, равна или меньше строки, на которую указывает s2.

Так что, пока результат соответствует этому описанию, он соответствует стандарту C. Это означает, что компилятор может выполнить оптимизацию в соответствии с этим определением.

Если мы посмотрим на ассемблерный код:

.loc 1 7 0
leaq    -32(%rbp), %rdx
leaq    -48(%rbp), %rax
movq    %rdx, %rsi
movq    %rax, %rdi
call    strcmp
movl    %eax, %esi
movl    $.LC0, %edi
movl    $0, %eax
call    printf
.loc 1 8 0
movl    $-1, %esi      # result of strcmp is precomputed!
movl    $.LC0, %edi
movl    $0, %eax
call    printf

В первом случае массивы передаются в strcmp для вызова strcmp и генерируются вызовы для printf. Однако во втором случае строковые константы передаются обоим. Компилятор видит это и сам генерирует результат, оптимизируя фактический вызов strcmp, и передает жестко закодированное значение -1 в printf.

person dbush    schedule 15.02.2019

из https://linux.die.net/man/3/strcmp

Функция strcmp() сравнивает две строки s1 и s2. Он возвращает целое число, меньшее, равное или большее нуля, если найдено, что s1 соответственно меньше, соответствует или больше s2.

Функция strcmp обещает вернуть только отрицательное значение для приведенного выше сравнения. Фактическое возвращаемое значение не указано.

Что, вероятно, произошло, так это то, что для strcmp("aa","ag") компилятор знает, что результат отрицательный, и оптимизирует его до -1.

person Rishikesh Raje    schedule 15.02.2019
comment
compiler knows the result is negative and optimises it to -1..какая возможная польза от этой оптимизации? - person Sourav Ghosh; 15.02.2019
comment
@SouravGhosh - с оптимизацией компилятор по-прежнему следует стандарту C и не требует вызова strcmp - person Rishikesh Raje; 15.02.2019
comment
@RishikeshRaje Хорошо, я не хотел, чтобы это было в комментариях - не могли бы вы добавить это к самому ответу? - person Sourav Ghosh; 15.02.2019
comment
@SouravGhosh - я думаю, что ценность и полезность любой оптимизации хорошо известны. Меньший код, лучшее время выполнения и т. д. - person Rishikesh Raje; 15.02.2019

Единственное, что стандарт C гарантирует для strcmp, это то, что знак возвращаемого значения будет указывать направление неравенства, если оно есть, или ноль, если строки точно равны.

Хотя возврат разницы между числовыми значениями char в первую очередь отличается тем, что они отличаются, является довольно распространенной реализацией, это не требуется. Если компилятор может смотреть на строковые константы и сразу знать, каким будет результат strcmp, он может добавить вместо него плоские -1, 1 или 0, вместо того чтобы прикладывать усилия к фактическому вызову функции.

Решение этой проблемы состоит в том, чтобы не писать код, основанный на конкретной реализации strcmp, какой бы распространенной она ни была. Доверяйте только знаку возвращаемого значения.

person Govind Parmar    schedule 15.02.2019