Преимущество использования short вместо int в for... loop
Есть ли какая-то польза от использования short вместо int в цикле for? т.е.
for(short j = 0; j < 5; j++) {
99% моих циклов содержат числа ниже 3000, поэтому я думал, что целые числа будут пустой тратой байтов. Спасибо!
8 ответов
Нет, никакой пользы нет. Короткое замыкание, вероятно, в конечном итоге займет полный регистр (32-битный, int) в любом случае.
Вы также потеряете часы, набрав дополнительные две буквы в IDE. (Это была шутка).
Нет. Переменная цикла, скорее всего, будет выделена регистру, поэтому она будет занимать одинаковое количество места независимо.
Посмотрите на сгенерированный ассемблерный код, и вы, вероятно, увидите, что используя int
генерирует более чистый код
с-код:
#include <stdio.h>
int main(void) {
int j;
for(j = 0; j < 5; j++) {
printf("%d", j);
}
}
используя короткий:
080483c4 <main>:
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
80483c7: 83 e4 f0 and $0xfffffff0,%esp
80483ca: 83 ec 20 sub $0x20,%esp
80483cd: 66 c7 44 24 1e 00 00 movw $0x0,0x1e(%esp)
80483d4: eb 1c jmp 80483f2 <main+0x2e>
80483d6: 0f bf 54 24 1e movswl 0x1e(%esp),%edx
80483db: b8 c0 84 04 08 mov $0x80484c0,%eax
80483e0: 89 54 24 04 mov %edx,0x4(%esp)
80483e4: 89 04 24 mov %eax,(%esp)
80483e7: e8 08 ff ff ff call 80482f4 <printf@plt>
80483ec: 66 83 44 24 1e 01 addw $0x1,0x1e(%esp)
80483f2: 66 83 7c 24 1e 04 cmpw $0x4,0x1e(%esp)
80483f8: 7e dc jle 80483d6 <main+0x12>
80483fa: c9 leave
80483fb: c3 ret
используя int:
080483c4 <main>:
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
80483c7: 83 e4 f0 and $0xfffffff0,%esp
80483ca: 83 ec 20 sub $0x20,%esp
80483cd: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
80483d4: 00
80483d5: eb 1a jmp 80483f1 <main+0x2d>
80483d7: b8 c0 84 04 08 mov $0x80484c0,%eax
80483dc: 8b 54 24 1c mov 0x1c(%esp),%edx
80483e0: 89 54 24 04 mov %edx,0x4(%esp)
80483e4: 89 04 24 mov %eax,(%esp)
80483e7: e8 08 ff ff ff call 80482f4 <printf@plt>
80483ec: 83 44 24 1c 01 addl $0x1,0x1c(%esp)
80483f1: 83 7c 24 1c 04 cmpl $0x4,0x1c(%esp)
80483f6: 7e df jle 80483d7 <main+0x13>
80483f8: c9 leave
80483f9: c3 ret
Чаще всего попытка оптимизации для этого только усугубляет ошибки, когда кто-то не замечает (или забывает), что это узкий тип данных. Например, посмотрите на проблему с bcrypt, которую я рассмотрел... довольно типично:
Тем не менее проблема все еще там, как int
это конечный размер, а также. Лучше потратить время на то, чтобы убедиться, что ваша программа правильная, а не создает опасности или проблемы с безопасностью из-за переполнения и переполнения чисел.
Некоторые из того, что я говорю о ж /numeric_limits
здесь может быть информативным или интересным, если вы еще не сталкивались с этим:
Как сказали многие другие, в вычислительном отношении нет никаких преимуществ и может быть хуже. Однако, если переменная цикла используется в вычислениях, требующих короткого замыкания, то это может быть оправдано:
for(short j = 0; j < 5; j++)
{
// void myfunc(short arg1);
myfunc(j);
}
Все, что на самом деле делает, - это предотвращает появление предупреждающего сообщения, поскольку переданное значение будет преобразовано в int (в зависимости от компилятора, платформы и диалекта C++). Но выглядит чище, ИМХО.
Конечно, не стоит зацикливаться на этом. Если вы хотите оптимизировать, помните правила (забудьте, кто придумал это):
- не
- Сбой шага 1, первая мера
- Изменить
- Если вам скучно, выйдите, иначе перейдите к шагу 2.
Нету. Скорее всего, ваш счетчик окажется в регистре в любом случае, и они, как минимум, имеют такой же размер, как int
Я думаю, что нет большой разницы. Ваш компилятор, вероятно, будет использовать весь 32-битный регистр для переменной счетчика (в 32-битном режиме). Вы потратите всего два байта из стека, самое большее, в худшем случае (если не используется регистр)
Одно потенциальное улучшение по сравнению с int
как счетчик цикла unsigned int
(или же std::size_t
где применимо), если индекс цикла никогда не будет отрицательным. С помощью short
вместо int
не имеет значения в большинстве компиляторов, вот те, которые у меня есть.
Код:
volatile int n;
int main()
{
for(short j = 0; j < 50; j++) // replaced with int in test2
n = j;
}
g ++ 4.5.2 -march = native -O3 в Linux x86_64
// using short j // using int j
.L2: .L2:
movl %eax, n(%rip) movl %eax, n(%rip)
incl %eax incl %eax
cmpl $50, %eax cmpl $50, %eax
jne .L2 jne .L2
clang++ 2.9 -march=native -O3 в Linux x86_64
// using short j // using int j
.LBB0_1: .LBB0_1:
movl %eax, n(%rip) movl %eax, n(%rip)
incl %eax incl %eax
cmpl $50, %eax cmpl $50, %eax
jne .LBB0_1 jne .LBB0_1
Intel C++ 11.1 - быстрый на x86_64 linux
// using short j // using int j
..B1.2: ..B1.2:
movl %eax, n(%rip) movl %eax, n(%rip)
incl %edx incl %eax
movswq %dx, %rax cmpl $50, %eax
cmpl $50, %eax jl ..B1.2
jl ..B1.2
Sun C++ 5.8 -xO5 на спарке
// using short j // using int j
.L900000105: .L900000105:
st %o4,[%o5+%lo(n)] st %o4,[%o5+%lo(n)]
add %o4,1,%o4 add %o4,1,%o4
cmp %o4,49 cmp %o4,49
ble,pt %icc,.L900000105 ble,pt %icc,.L900000105
Итак, из четырех имеющихся у меня компиляторов только один даже имел разницу в результате, и он фактически использовал меньше байтов в случае int.