Добавление подробностей в ответ @hobbs для архитектуры x86-64. Соглашение о вызове функции x86-64 заключается в том, что первые шесть целочисленных или указательных параметров передаются в регистрах
% rdi,% rsi,% rdx,% rcx,% r8 и% r9
, тогда как первые шестнадцать параметров с плавающей запятой передаются в регистрах
% xmm0 -% xmm15
В этом случае первый параметр printf является строкой форматакоторый является указателем, поэтому он будет передан в % rdi , второй аргумент является целым числом, поэтому он будет передан в% rsi. Третий аргумент является числом с плавающей запятой, поэтому он будет передан в регистр% xmm0.
Внутри printf первого аргумента строка формата будет считана из% rdi, теперь она обработает строку формата и найдет "% f ", поэтому он будет читать% xmm0, потому что там, где должен находиться первый аргумент с плавающей точкой, он находит« 3.14 »в% xmm0 и печатает его правильно, затем снова просматривает строку формата и находит% d, поэтому он читаетрегистр% esi, который будет иметь второй целочисленный аргумент, находит там 42 и печатает его правильно.
Поскольку существует шесть регистров для передачи целых чисел / указателей и 16 для передачи плавающих точек, следующее также работает
int main() {
printf("%d %d %d %d %d %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0, 40, 41, 42,
43,44);
}
Выход: 40 41 42 43 44 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 9.000000 10.000000 11.00000000 12.000000 13.000000 14.000000 15.000000 16.000000