printf переменной int с идентификаторами типов lld, ld и d - PullRequest
0 голосов
/ 27 октября 2019

Как я думаю,% d в printf будет читать sizeof (int) из стека, а% ld будет читать sizeof (long) из стека и так далее для% lld. Я написал этот фрагмент кода:

##############printf1.c
#include <stdio.h>

int main()
{
    int a = 1, b = 2;
    long la = 1, lb = 2;
    long long lla = 1, llb = 2;

    printf("a=%d, b=%d\n", a, b); 
    printf("a=%ld, b=%ld\n", a, b); 
    printf("a=%lld, b=%lld\n", a, b); 

    printf("la=%d, lb=%d\n", la, lb);
    printf("la=%ld, lb=%ld\n", la, lb);
    printf("la=%lld, lb=%lld\n", la, lb);

    printf("lla=%d, llb=%d\n", lla, llb);
    printf("lla=%ld, llb=%ld\n", lla, llb);
    printf("lla=%lld, llb=%lld\n", lla, llb);

    return 0;
}

И вывод на моей машине был:

$ ./printf1
a=1, b=2
a=1, b=2
a=1, b=2
la=1, lb=2
la=1, lb=2
la=1, lb=2
lla=1, llb=2
lla=1, llb=2
lla=1, llb=2

Как это произошло? Я думаю, что должны быть некоторые ненужные выходные данные, если тип переменной и идентификатор типа не совпадают. Мой компьютер:

$ uname -a
Linux cu01 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Мой gcc:

$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)

пс: Я прочитал этот пост: printf переменной size_t с идентификаторами типов lld, ld и d .Но проблема автора не возникла в моем тесте. Что касается кода автора:

##############printf2.c
#include <stdio.h>
int main()
{
    size_t temp;
    temp = 100;

    printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp);
    printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp);

    return 0;
}

Результат вывода на моей машине всегда "правильный":

$ ./printf2
lld=100, ld=100, u=100
ld=100, u=100, lld=100

Может кто-нибудь дать объяснение этим? Большое спасибо за вашу помощь!

1 Ответ

0 голосов
/ 27 октября 2019

Это действительно происходит из-за комбинации того, как эти значения передаются в printf и как они читаются. Итак, прежде всего причина того, что вы получаете правильный результат при передаче его в printf с использованием спецификатора d, заключается в том, что он читает только первые 4 байта из вашего 8-байтового целого числа, так уж получилось, что число 1 принимает толькодо одного байта, поэтому независимо от того, сколько байт он читает, он напечатает 1. Вот простой способ визуализировать его.

вот как выглядит ваше длинное (и длинное длинное) число в двоичном виде

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
                                   |-----------------------------------|

выше показаны биты, которые считываются, когда вы передаете его, используя d в качестве спецификатора, если вы передадите ld или lld в качестве спецификатора, он будет считывать оставшиеся 4 байта, но так как они естьвсе ведущие нули это, очевидно, не влияет на результат печати. Эта же концепция применима к числу 2. Попробуйте заменить значение la и lla на LONG_MAX, и вы заметите, что оно печатает -1 при использовании со спецификатором d. Обратите внимание, что это поведение не определено, потому что оно зависит от порядкового номера системы и не будет происходить во всех системах, это именно то, что наиболее вероятно происходит в вашей системе.

Теперь, почему это не разрушает стек? это, очевидно, должно быть, если мы не будем честны в отношении размера вещей, передаваемых в стек, верно? Итак, поскольку вы работаете в системе Linux, ваша машина использует System V abi, которая в соглашении о вызовах указывает, что первые несколько аргументов должны передаваться с помощью регистров, поэтому в этом случае на самом деле ничего не помещается в стек, ивсе это читается из регистров. Вот еще немного информации, если вы хотите узнать больше об этом https://wiki.osdev.org/Calling_Conventions

Важно отметить, что это приводит к разным результатам на разных машинах, поэтому, очевидно, это называется неопределенным поведением и почему вы не должны полагатьсяиспользовать его или вообще использовать в своем коде, особенно если в таких ситуациях это не так просто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...