nixp.ru v3.0

24 января 2017,
вторник,
08:07:36 MSK

DevOps с компанией «Флант»
Аватар пользователя rgo
rgo написал 25 апреля 2008 года в 23:57 (420 просмотров) Ведет себя неопределенно; открыл 61 тему в форуме, оставил 1602 комментария на сайте.

Вот такой кусок кода:

int main ()
{
    pid_t pid = getpid ();
    printf ("Hi. My pid is %d\n", pid);
    return 0;
}

Всё замечательно и хорошо, но встаёт вопрос: правильно ли использовать %d для типа pid_t? Для size_t? Для всех прочих типов typedef’нутых от чего-нибудь целочисленного?

На x86 практически всё по 32-бита и вопросов не возникает: хочется вывести размер массива, который size_t? Пишем %d. А на x86_64 уже всё чуть сложнее. Например, size_t уже 64 бита, а %d выковыривает из стека лишь 32-битную переменную. Как в такой ситуации написать программу, которая одинаково хорошо будет компилироваться и на 32-битной платформе, и на 64-битной?

Варианта напрашивается два: либо использовать ifdef’ы и форматную строку менять. Но это неудобно. Либо всё, что может вызывать вопросы кастить к (long long) и выводить как %lld. (Кстати даже на x86 я подчастую сумлевался писать %d или %u, но это как правило некритично).

Ах, да, в качестве третьего варианта, можно забить на C и использовать C++ с его перегруженными функциями/операторами. Но это неинтересно.

Собственно, интересно, как бы так покрасивее решить эту проблему разнобитовой совместимости.

ps. я как-то натыкался на статейку, в которой, насколько я помню, было приемлимое решение, но мне она тогда была неинтересна, и я её по диагонали тогда глазом пробежал, а сегодня уже и не вспомнить как это делать. И статью не найти. :(

rgo

Здоровый ночной сон принёс решение :)

#define PIDTFMT "%d"
...
printf ("Hi. My pid is " PIDTFMT "\n", pid);

Лучше, по-моему, не выйдет.

metal

Почему не просто

printf ("Hi. My pid is %ld\n", pid);


?

И если есть сомнения можно явно сделать:

printf ("Hi. My pid is %ld\n", (long int)pid);
rgo
metal
Почему не просто

printf ("Hi. My pid is %ld\n", pid);

?

Потому что, если речь идёт о 64-битной платформе, то второй аргумент printf’а, положит в стек четыре байта, а printf, увидев %ld, прочитает 8. На 32-битной, по-моему всё сработает, там вроде sizeof (int) == sizeof (long).

А касты мне не нравятся. Потому что если следовать идее до конца, придётся всё (pid_t, size_t, off_t и пр) конвертать в 64-бита внезависимости от платформы.

metal
rgo
Потому что, если речь идёт о 64-битной платформе, то второй аргумент printf’а, положит в стек четыре байта, а printf, увидев %ld, прочитает 8.

Я могу ошибаться, то на 64-битной pid_t должен быть 8 байт.

metal

Вот глянул исходники ядра, 32-й он на обоих. На мой взгляд не правильно, решать использовать дополнительные #define, об этом позаботились уже разработчики ядра и надо просто правильно ставить модификатор. Так для pid_t он должен быть «%d».

rgo

А с size_t, что делать?

metal

Он как раз long и должно быть «%ld».

rgo
metal
Он как раз long и должно быть «%ld».

Размер long’а различен для 64-битных linux и windows. size_t же, наверное, одинаков.

myst

size_t = unsigned long на каждой архитектуре. Грубо говоря, size_t — это тип адреса, его malloc() возвращает. На 64-битной платформе size_t = 64 бита.

rgo
myst
size_t = unsigned long на каждой архитектуре. Грубо говоря, size_t — это тип адреса, его malloc() возвращает. На 64-битной платформе size_t = 64 бита.

Тогда я чего-то непонимаю в этой жизни. Вот ссылочка: http://www.ibm.com/developerworks/library/l-port64.html, там есть табличка размеров целочисленных типов для разных «data models». Если твоё высказывание есть истина, то к чему тогда там эта табличка? Точнее столбец озаглавленный LLP64, где sizeof(long)!=sizeof(void*)

При этом, я видел табличку соответствия размеров типов в 64-битном лине и 64-битной венде. Ссылку мне искать лень, но я точно помню что они различались в размерах типа long.

myst

http://www.osdev.org/wiki/X86-64

См. Models used by 64bit OSs

rgo

Да. Вендовс пользует LLP64. Но ведь, я как рассуждаю: sizeof(size_t) должен равен размеру адреса, иначе нафига весь этот сыр-бор с 64-мя битами. То есть sizeof(size_t)==8. Но в виндовс, в LLP64, sizeof(long)==4 => sizeof(long)!=sizeof(size_t).

Но

size_t = unsigned long на каждой архитектуре

Противоречие. :)

myst

Ну да, подменил понятия немного. Я Unix имел ввиду.

ecobeingecobeing.ru
Экология и вегетарианство на благо всем живым существам Планеты.