[freebsd] printf в clang

spell at itl.ua spell at itl.ua
Fri Dec 31 10:20:44 EET 2021


30 декабря 2021 г., 23:39, "Valentin Nechayev" <netch at netch.kiev.ua> написал:

> hi,
> 
> Thu, Dec 30, 2021 at 21:15:36, spell wrote about "[freebsd] printf в clang": 
> 
>> int64_t bv;
>> long cid;
>> bv = ( (int64_t) 1 << 33) + 3;
>> cid = 111;
>> printf("%ld %ldn", bv, cid);
> 
> Тут наверно должно было быть \n в конце форматной строки.

опечатка :(

>> clang резонно выдает варнинг о несоответствии типа первого аргумента (%ld вместо правильного %lld).
> 
> Компиляция в 32 битах, я так понимаю? Потому что в 64 проблем не
> видно.

да.

>> А вот вывод этой программы менее ожидаем:
>> 
>> 3 2
>> 
>> Первое число ожидаемо - младшие 4 байта от bv.
>> А второе, вместо значения cid - старшие 4 байта от bv.
>> 
>> clang version 10.0.1.
> 
> Именно что если в 32 битах, то всё логично, потому что:
> 1. При передаче в переменном наборе аргументов (как printf) происходит
> расширение всех целочисленных типов, которые у́же int, к int, а более
> широкие не меняются.
> 2. Соглашение о вызове предусматривает передачу всех аргументов на
> стеке. Соответственно в позиции начала переменной области аргументов
> укладывается: 03 00 00 00 02 00 00 00 (bv) 6f 00 00 00 (cid).
> 3. printf согласно формату %ld извлекает long, который в этом режиме
> 32 бита (равен int). Извлекается 03 00 00 00 (значение 3).
> Второй %ld извлекает 02 00 00 00 (значение 2).

Так и предположила.
Собственно, вопрос - это считается за баг, или "сам виноват"?
Варнинг, конечно, это хорошо, но и обработка ситуации тоже важна.
Вот например такой код:

printf("%ld %ld\n", bv, cid, cid);

выдаст варнинг насчет лишнего аргумента, но значение cid не выведет,
хотя в стеке аргументов место для этого второго cid есть.

> В 64 битах проблемы не будет, потому что:
> 
> 1. Первые 6 аргументов передаются в регистрах, включая переменные
> аргументы (! - из-за этого va_arg c компанией заметно усложняется).
> Форматная строка будет в rdi, bv - в rsi, cld - в rdx.
> 2. long и long long одинаково имеют 64 бита ширины и передаются
> соответственно в полную ширину регистра.

Спасибо, очень интересно, буду знать!


More information about the freebsd mailing list