Бинтуронги и лемуры
Большую часть своей жизни я прожил кошатником, но несколько лет во время очередного самокопания, внезапно понял, что теперь я собачник. Не знаю как так случилось, но на улице я скорее поглажу
Но есть в моём сердце место и для других животных, с которыми мне было очень интересно пообщаться.
В Таиланде мне очень понравились бинтуронги. Для нас это экзотика — больше ни в одном зоопарке мира они мне не попадались. Животные очень милые и общительные, жаль только, что ночные — днём они
По характеру любопытные, но очень тактичные. Не помню чем мы их там кормили, но ни разу не было такого, чтобы они сами выхватили у нас еду, как это делают обезьяны, например. Ещё у них очень сильный хвост — они даже могут на нём висеть, пока держишь их на руках, они всё время очень трогательно им за вас цепляются.
В Китае довелось потрогать лемуров. Они более бесцеремонные, но при этом всё равно очень милые. Куда более своенравные и независимые — не могу себе представить, чтобы их можно было подержать на руках, как кошку или погладить полной ладонью. Бинтуронги на такое соглашались с полной готовностью.
Интересно, что лемуры очень неохотно подходят, если стоишь к ним лицом, может быть это для них признак агрессии, как для макак, когда им смотришь в глаза. Вот если подставить спину — почти сразу прыгают и потом с удовольствием сидят на плече, выбирая что именно ты им там даёшь в качестве корма.
Есть животное, с которым я бы очень хотел пообщаться, но вряд ли доведётся — это красная панда. Впервые близко я её увидел в зоопарке Барселоны в 2014 году. Позже мы ещё специально дважды летали в Москву, чтобы показать её дочке, которой она тоже очень нравится. Дважды, потому что в первый раз панда так и не вышла из домика в вольере.
Маленькая сбойная программа на Си
Попалась мне тут статья про задачку, которую автору задали в университете — написать самую маленькую (по объёму текста) программу на Си, которая компилируется, но выполняется с ошибкой. Прежде чем читать, я попробовал написать такую самостоятельно.
Сначала я подумал о рекурсии:
main(){main();}Для экономии байт можно использовать стандарт Си89, где всё, у чего нет при определении задания типа, имеет тип int — это позволяет убрать тип функции main.
Программа компилируется, но, как и задумывалось, падает с ошибкой:
bolk@note ~$ gcc-14 -std=c89 small.c && ./a.out
Segmentation fault: 11Дальше я подумал, что вряд ли в статье используется такой очевидный способ и, перебрав в уме несколько вариантов, решил сосредоточится на делении на ноль. Лучший вариант, который мне пришёл в голову, вот такой, он на один байт меньше:
main(a){a/=0;}Очевидная идея — поделить число на ноль и никуда не присваивать, работать не будет, компилятор просто выкинет константное выражение. Поэтому его надо или присвоить переменной или вернуть. return занимает больше присваивания, но куда бы мы могли присвоить? Нужна же переменная.
Переменную можно взять из аргументов функции main, в первый её аргумент записывается число параметров при вызове. Если ноль поделить на ноль, это ошибки не вызовет, но там всегда не ноль, потому что нулевой параметр всегда существует и содержит имя программы.
Поэтому мы можем поделить его на ноль и программа упадёт при вызове:
bolk@note ~$ gcc-14 -std=c89 -Wno-div-by-zero small.c && ./a.out
Floating point exception: 8Но самая короткая сбойная программа оказалась почти втрое меньше. Выглядит она так:
main;Она компилируется, хоть и с замечанием, и падает, как и требуется по условию:
bolk@note ~$ gcc-14 -std=c89 small.c && ./a.out
small.c:1:1: warning: data definition has no type or storage class
1 | main;
| ^~~~
Bus error: 10Тут определяется статическая переменная main с неявным заданием типа int, которая, как все такие переменные, инициализируется нулём. Поскольку компоновщик видит имена, но ничего не знает о типах, он связывает адрес переменной с адресом точки входа в программу. Когда программа запускается, управление передаётся по адресу ноль, что вызывает ошибку.
Ошибка вызывается, кстати, потому что адрес ноль является зарезервированным значением в Си. Ноль обозначает, что указатель пустой (имеет значение NULL), поэтому при обращении к нему срабатывает специальная ловушка, вызывающая ошибку. Правда это возможно только на платформах с защитой памяти.
Добавлено: Оказалось, что я неправильно разобрался в происходящем.