За вход 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 = 0x2aaaaaaa
v2 = 0x02222222
По-долу са разглобени инструкции за реда "int v1 = count >> 2;" с -O0 и -O1.
С -O0:
sarl $0x2, %esi
С -O1:
shrl $0x2, %esi
По-долу са разглобени инструкции за реда "int v2 = v1 & mask2;" с -O0 и -O1.
С -O0:
andl -0x24(%ebp), %esi //-0x24(%ebp) съхранява 0x33333333
С -O1:
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
, така че изпращането на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