Почему функция возвращает два разных значения, даже если в вызове функции ничего не изменилось? - PullRequest
1 голос
/ 26 июня 2019

В первом случае код возвращает -1

#include <iostream>

template <typename T>
int compare( const T &val1, const T &val2){

    if(val1 < val2) return -1;
    if(val2 < val1) return 1;
    return 0;
}

int main(){

    std::string v1= "hello", v2 = "world";
    std::cout << compare("hello", "world") << std::endl;
}

Во втором случае код возвращает 1, даже если в вызове метода нет изменений.

#include <iostream>

template <typename T>
int compare( const T &val1, const T &val2){

    if(val1 < val2) return -1;
    if(val2 < val1) return 1;
    return 0;
}

int main(){

    std::cout << compare("hello", "world") << std::endl;
}

Iиспользую g ++ 7.4.0.

Ответы [ 2 ]

1 голос
/ 26 июня 2019

Использование таких операций, как <, для указателей, которые не указывают на элементы вменяемого массива, является неопределенным поведением.Разные строковые литералы являются разными массивами и распадаются на указатели на элементы разных массивов.Любой результат возможен.Либо программа может вывести 0, либо вывести из строя, либо запустить ядерную боеголовку, либо выполнить одно из этих действий сегодня, а другое - завтра.И, конечно, две программы с UB, которые отличаются, казалось бы, несущественными деталями (например, v1, v2 в вашем случае), также могут вести себя по-разному.Ничто из этого не предсказуемо.

1 голос
/ 26 июня 2019

В обоих случаях T определяется как char [6]. При сравнении массив распадается на указатель на первый элемент массива - char*. Таким образом, вы сравниваете два указателя, и результат непредсказуем, потому что вы не знаете, как эти строковые литералы - «привет» и «мир» - помещаются в память, у которой более низкий адрес.

Вы получаете 0 (что должно быть невозможно, потому что привет и world , поскольку строковые литералы не могут занимать одну и ту же память), потому что эти условия

if(val1 < val2) return -1;
if(val2 > val1) return 1;    // condition val1 > val2 was not tested
// return 0

одинаковы. Должно быть:

if(val1 < val2) return -1;
if(val1 > val2) return 1;

Посетите GodBolt и посмотрите, какой код генерируется, когда строка

std::string v1= "hello", v2 = "world";

прокомментировано.

[1], когда не комментируется код:

.LC0:
        .string "hello"
.LC1:
        .string "world"
main:
        push    rbp
        mov     rbp, rsp
        push    rbx

[2] при комментировании

.LC0:
        .string "world"
.LC1:
        .string "hello"
main:
        push    rbp
        mov     rbp, rsp
        mov     esi, OFFSET 

Вы видите это сейчас? LC0 и LC1 являются памятью меток (некоторые значения сравниваются), поэтому вывод непредсказуем, зависит от того, как компилятор хранит строковые литералы в памяти, что является первым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...