#include <stdio.h>
#include <math.h>
int main(int argc, const char *argv[])
{
long i, max;
long sum = 0;
max = (long)pow(2,32);
for (i = 0; i < max; i++) {
sum += i;
}
printf("%ld\n", sum);
return 0;
}
$gcc -S main.c
Возникает вопрос: в коде .L2
ниже -8(%rbp)
всегда равен нулю, а %rax
всегда больше нуля. Итак, это бесконечный цикл? И если я компилирую с gcc -S -O1 main.c
, это очень ясно. Я действительно обеспокоен!
Просто небольшая часть кода ассемблера:
main:
pushq %rbp
movq %rsp, %rbp
subq $48, %rsp
movl %edi, -36(%rbp)
movq %rsi, -48(%rbp)
movq $0, -16(%rbp)
movl $0, -8(%rbp)
movl $2, -4(%rbp)
movq $0, -24(%rbp)
jmp .L2
.L3:
movq -24(%rbp), %rax
addq %rax, -16(%rbp)
addq $1, -24(%rbp)
.L2:
movq -24(%rbp), %rax
cmpq -8(%rbp), %rax
jl .L3
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
Счетчик реального цикла (i
) находится в -24(%rbp)
. На третьей линии он увеличился. На 4-й строке он загружается в rax
. Таким образом, rax
не является постоянным нулем, он пробегает значения вместе с i
.
-8(%rbp)
, предполагается, что это max
. Таким образом, значение i
сравнивается с этим, и это условие выхода из цикла. -8(%rbp)
не должно быть равно нулю. Если это так, я ощущаю 32-битную арифметику изгоев.
EDIT: Я думаю, я знаю, в чем дело. Константы 2 и 32 являются int
, но не long
, поэтому предполагается, что они 32-битные. Размер int
зависит от платформы; даже конвенция GCC может отличаться. pow(int, int)
реализуется как неотъемлемая. 2 ^ 32 равно 0, когда аргументы 32-битные.
замещать
max = (long)pow(2,32);
с
max = pow(2l, 32l);
Или лучше с константой:
max = 0x100000000l;
Как и я и другие подозреваемые, в миксе был кусок 32-бит.
Нет, это не бесконечный цикл. Прежде всего% rax не всегда больше 0, в этой строке он получает значение из -24 (% rbp), который, очевидно, является переменной i
. Когда он входит в цикл, он устанавливает -24 (% rbp) в ноль, а затем переходит к.L2. Это частично происходит, что вы не показывали. Если -8 (% rbp), который является значением переменной max
, равен нулю (в случае переполнения) jl
не будет переходить на.L3, и цикл будет завершен после первой проверки. Я не совсем понимаю, почему вам нужно прочитать сборку для этого, что довольно очевидно из C++ исходного кода.
printf()
должны помочь.
-8(%rbx)
инициализируется нулем, выше которого я добавил дополнительные коды. и в первый раз cmpq -8(%rbx), %rax
имеет значение true, затем всегда true, если %rax
не переполнится.
long
? Если это 32 бита (4 байта), тоpow(2, 32)
будет переполнен. Если вы хотите получить максимальное значениеlong
, то вам следует использоватьstd::numeric_limits
в C ++ иLONG_MAX
из заголовочного файла<limits.h>
в C.-8(%rbp)
- значениеmax
поэтому оно не должно быть нулевым. Может быть, вы могли бы показать больше ассемблера, где он установлен.