Программист написал функцию для перевода чисел в двоичную систему счисления.
# принимает число, возвращает строку -- двоичное представление этого числа
sub dec2bin
{
my $dec = shift;
my $bin = "";
while ($dec > 0){
# Если очередной остаток от деления на 2 равен 1, приписываем к двоичной записи 1, иначе -- 0
$dec % 2? $bin = 1 . $bin : $bin = 0 . $bin;
# делим исходное число на 2
$dec >>= 1;
}
return $bin;
};
Можно скачать код: здесь.
Однако работает функция как-то странно. Что с ней не так?
dec2bin(2)
возвращает ‘00’, dec2bin(9)
– ‘0000’, а dec2bin(2013)
- ‘00000000000’.
Все-таки использовать оператор ?:
вместо if
– странноватая идея.
Дело в том, что у тернарного оператора ?:
приоритет выше, чем у присваивания.
Поэтому выражение
$dec % 2? $bin = 1 . $bin : $bin = 0 . $bin;
вычисляется как
($dec % 2? $bin = 1 . $bin : $bin) = 0 . $bin;
Что интересно: в языке C приоритет ?:
тоже выше, чем у присваивания.
Однако в C выражение вида c ? i+=1 : i+=2
не пройдет компиляцию
( gcc выдает сообщение ‘lvalue required as left operand of assignment’),
потому что выражение c ? i+=1 : i
не может служить левой частью присваивания.
А вот в Perl результат выражения ($dec % 2? $bin = 1 . $bin : $bin)
–
корректное Л-значение, которое можно использовать в левой части присваивания.
Получается так потому, и вторая и третья часть в ?:
– Л-значения.
$bin
– переменная, а присваивание из второй части ($bin = 1
)
тоже возвращает Л-значение, переменную из своей левой части.
См. также perldoc perlop.
Так что программисту стоило бы по крайней мере поставить скобки:
$dec % 2? ($bin = 1 . $bin) : ($bin = 0 . $bin);
А еще лучше – использовать обыкновенный if
.
Из наших читателей наиболее точное описание проблемы прислал Тигран Оганесян. Здорово!