C: Почему & = лучше =? - PullRequest
       19

C: Почему & = лучше =?

2 голосов
/ 09 января 2020

Я смотрю на какой-то старый код, который я унаследовал, и мне действительно не нравится стиль в некоторых местах. Одна из вещей, которые мне действительно не нравятся, это что-то вроде:

bool func() {
    bool ret = true;

    ret &= test1();
    homemade_assert_like_function(ret == true);
    ret &= test2();
    homemade_assert_like_function(ret == true);

    return ret;
}

Где я думаю, что следующее выглядит намного чище:

bool func() {
    homemade_assert_like_function(test1());
    homemade_assert_like_function(test2());

    return true; // just to keep the interface
}

Однако последнее производит больше ассемблерного кода. Неудивительно, что если я изменю &= с первого примера на =, результат будет таким же, как assert(test());, но все же &= будет лучше

Я использую gcc5.4 для mips с -O2 для всех трех примеров, но результат аналогичен, если я использую g cc для р c. Если я скомпилирую с -std = c ++ 14 (и более новым компилятором), три примера приведут к одному и тому же коду.

Может кто-нибудь объяснить мне это? Это просто мой тестовый код, который действительно плох?

РЕДАКТИРОВАТЬ: я сделал новый пример кода, исправляя сломанный assert. У него был интересный побочный эффект. Разница в размерах теперь намного меньше, что говорит мне о том, что оптимизатор может совершить магию c в случае &=.

https://godbolt.org/z/Vk6uoY

Как уже указывалось несколько раз, пример кода несколько запутан. Но он показывает то же самое, что я вижу в реальном коде - то, что ничего не меняя, кроме удаления кода стиля &=, увеличивает базу кода.

Ответы [ 2 ]

3 голосов
/ 09 января 2020

Этот код пытается использовать ярлык для оценки, но он не работает.
(код неверен)

Во-первых, позвольте мне показать, что это такое означало сделать:

Код должен был выглядеть так:

bool func() {
    bool ret = true;

    ret = ret && test1();
    homemade_assert_like_function(ret == true);

    ret = ret && test2();
    homemade_assert_like_function(ret == true);

    return ret;
}

Важной частью является то, что если ret уже false, указывая, что результат не удался Он даже не попытается оценить вторую часть выражения! (test1() или test2()).

Если функция test() имеет какие-либо побочные эффекты, она не будет запускаться, если флаг ret указывает на сбой.

Это полезно для прохождения длинного многошагового процесса (test1() ... testN()) и не выполнения какой-либо работы после сбоя одного шага.


Теперь, что это за код на самом деле делает, и почему?

ret начинается как true, и как только одна из функций выходит из строя, ret становится false и застревает на false (пока операция выполняется всегда &=.

Но, в отличие от того, что я написал выше, каждая функция, test1(), test2(), testN(), все равно запускается (включая побочные эффекты), даже если предыдущий тест уже не удалось!

Это ничем не отличается от того, что если бы они только что написали код как:

bool func() {
    bool ret = true;

    ret = test1();
    homemade_assert_like_function(ret == true);
    ret = test2();
    homemade_assert_like_function(ret == true);

    return ret;
}

Большое отличие от кода, который вы предлагаете, заключается в том, что ваш код всегда возвращает true. Как вы можете предположить, что каждый тест прошел успешно? Коду должно быть разрешено возвращать false, если тест не пройден s. Вы удалили эту функцию из своей версии кода.

0 голосов
/ 09 января 2020

Я думаю, что ваш тестовый код неоправданно сложен. Если вы разберете только саму функцию, вы увидите, что космеция c изменений в функции приводит к тому, что код становится практически идентичным. Фактически они приводят к немного более быстрому коду.

Я избавился от всей бессмысленной путаницы и написал читабельную версию:

#include <stdbool.h>

bool func (void) {
    assert(test1());
    assert(test2());
    return true;
}

11 инструкций по g cc x86-64 9.2 - O2. Но ваша оригинальная версия дает 15 инструкций. Изменение типов функций на bool приводит к немного другому коду, но все же чистая версия более эффективна.

https://godbolt.org/z/4Cmr_H

Важная часть здесь, однако, написать наиболее читаемый код . Писать такие странные вещи, как bool ret = true; ret &= test1();, просто бессмысленно.

...