Я хочу знать для себя, что происходит позади и почему он печатает nan, когда я использую его с %f, или длинное число, когда я использую его с %lf.
Некоторые причины.
Во-первых, printf не знает типы дополнительных аргументов, которые вы ему фактически передаете. Он полагается на строку формата, чтобы сообщить ему количество и типы дополнительных аргументов, которые нужно ожидать. Если вы передадите size_t в качестве дополнительного аргумента, но скажете printf ожидать float, то printf будет интерпретировать битовую комбинацию дополнительного аргумента как float, а не size_t. Целочисленные типы и типы с плавающей запятой имеют совершенно разные представления, поэтому вы получите значения, которых не ожидаете (включая NaN).
Во-вторых, разные типы имеют разные размеры. Если вы передадите 16-битное short в качестве аргумента, но скажете printf ожидать 64-битного double с %f, то printf будет искать дополнительные байты сразу после этого аргумента. Не гарантируется, что size_t и double имеют одинаковые размеры, поэтому printf может либо игнорировать часть фактического значения, либо использовать байты из памяти, которые не являются частью значения.
Наконец, это зависит от того, как передаются аргументы. В некоторых архитектурах для передачи аргументов (по крайней мере, для первых нескольких аргументов) используются регистры, а не стек, и разные регистры используются для чисел с плавающей запятой и целых чисел, поэтому, если вы передаете целое число и сообщаете ему ожидать двойное значение с %f, printf может посмотрите не в том месте и напечатайте что-то совершенно случайное.
printf не умный. Он зависит от того, используете ли вы правильный спецификатор преобразования для типа аргумента, который вы хотите передать.
23.10.2019