Для ввода 0xffffffff следующий код c работает нормально без оптимизации, но дает неверные результаты при компиляции с параметром -O1. Другие параметры компиляции: -g -m32 -Wall. Код протестирован с clang-900.0.39.2 в macOS 10.13.2.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc < 2) return 1;
char *endp;
int x = (int)strtoll(argv[1], &endp, 0);
int mask1 = 0x55555555;
int mask2 = 0x33333333;
int count = (x & mask1) + ((x >> 1) & mask1);
int v1 = count >> 2;
printf("v1 = %#010x\n", v1);
int v2 = v1 & mask2;
printf("v2 = %#010x\n", v2);
return 0;
}
Ввод: 0xffffffff
Выходы с -O0: (ожидается)
v1 = 0xeaaaaaaa
v2 = 0x22222222
Выходы с -O1: (неправильно)
v1 = 0x2ааааааа
v2 = 0x02222222
Ниже приведены дизассемблированные инструкции для строки "int v1 = count >> 2;" с -O0 и -O1.
С -O0:
сарл $0x2, %esi
С -О1:
шрл $0x2, %esi
Ниже приведены дизассемблированные инструкции для строки "int v2 = v1 & mask2;" с -O0 и -O1.
С -O0:
andl -0x24(%ebp), %esi //-0x24(%ebp) сохраняет 0x33333333
С -О1:
andl $0x13333333, %esi //почему оптимизация меняет 0x33333333 на 0x13333333?
Кроме того, если для x локально установлено значение 0xffffffff вместо получения его значения из аргументов, код будет работать должным образом даже с -O1.
P.S. Код представляет собой экспериментальную часть, основанную на моем решении Data Lab из курса CS:APP @ CMU. Лабораторная работа просит студента реализовать функцию, которая подсчитывает число 1 бит переменной int без использования какого-либо другого типа, кроме int.
0xffffffff
это ›MAX_INT
в вашем случае, а переполнениеint
является неопределенным поведением. - person Stargateur   schedule 22.12.2017unsigned int
по многим причинам, битовый оператор следует использовать только сunsigned integer
,printf("v1 = %#010x\n", v1);
=>%x
ожидатьunsigned int
, поэтому поведение undefined для отправкиint
. - person Stargateur   schedule 22.12.2017-O0
, так и для-O1
- person yano   schedule 22.12.2017#include
- person user3629249   schedule 22.12.2017argv[0]
без предварительной проверкиargc
, чтобы убедиться, что пользователь действительно ввел ожидаемый параметр командной строки - person user3629249   schedule 22.12.2017int count = (x & mask1) + ((x >> 1) & mask1);
приведет к переполнению переменнойcount
Предложите привести выражения кssize_t
или лучшеint64_t
и объявитьcount
как более длинный тип. - person user3629249   schedule 22.12.2017strtol()
- person user3629249   schedule 22.12.2017int
повсюду. Неаккуратная типизация имеет тенденцию приводить к различным формам плохо определенных ошибок поведения и всегда приводит к полностью непереносимому коду. Профессиональные программисты используютstdint.h
. - person Lundin   schedule 22.12.2017