что тут делал printf? - PullRequest
       27

что тут делал printf?

2 голосов
/ 24 марта 2020

Просто я проверял свое понимание указателей, при этом я делал это,

Хорошо, это то, что я думаю. Все указатели на любой тип содержат адреса, верно? Скажи, что я заявляю char *a, b = 'f'; a = &b ; Поэтому, когда я пытаюсь получить доступ к содержимому b, то есть & b, через указатель на тип char.which, что нормально.

Но, что если я сохраню адрес типа данных int в указателе типа char (хотя я получить предупреждение: присвоение из несовместимого типа указателя [-Wincompatible-pointer-types], я не делаю неправильно, верно? я все еще храню адрес некоторой памяти.)

int main(){
// int type of one byte
    int a, i ;
    char *b;

    for(i = -256 ;i < 257; ++i){
        a = i;
        b = &a;
        printf("for i = %d, value stored in first byte of a = %d\n",i ,*b);
    }
    return 0;    
}

теперь я думал, что будет разрешено читать только первый байт из 4 байтов, выделенных для a , потому что я получаю доступ через указатель на тип символа, я ожидал сохранить значения до 255, за этим будет вид переполнения. но случилось что-то другое, я мог сохранить только 127 до -128, что! !! Вы видели это тип int размером один байт. Вы можете запустить код, чтобы увидеть.

Теперь предположим, что тип int имеет размер один байт

когда a = 256, значение чтения равно 0, что ожидается, поскольку 0001 0000 0000 будет считывать только первый байт. Вывод будет предсказуемым, пока мы не достигнем a = 127, который сохраняется как 0111 1111 (что является положительным значением с точки зрения типа int) когда a = 128, выходное значение равно -128, в котором хранится 1000 0000 (что действительно равно -128) аналогично можно объяснить и другие выводы Таким образом, вывод можно объяснить, предполагая, что тип int имеет размер один байт, почему printf сделал это вместо выдачи ошибки.

Итак, что именно здесь сделал printf? Спасибо, Ваши Превосходительства;)

Ответы [ 2 ]

4 голосов
/ 24 марта 2020

Ваша система использует подписанные символы, что совершенно нормально.

Похоже, вы предполагаете / ожидаете, что char будет unsigned, что не всегда верно. Он либо подписан, либо не подписан, но это зависит от реализации.

1 голос
/ 24 марта 2020

Но, что если я сохраню адрес типа данных int в указателе типа char (хотя я получаю предупреждение: присваивание из несовместимого типа указателя [-Wincompatible-pointer-types], я не делаю неправильно, верно? Я все еще храню адрес какой-то памяти.)

Да, вы делаете что-то не так, поэтому вы получаете предупреждение.

Тип указателя имеет значение по двум причинам:

  1. Арифметика указателя c выполняется в терминах объектов, а не байтов. Если p является char *, а его значение является адресом объекта char (скажем, 0x1000), то p + 1 оценивает адрес следующего объекта char (0x1001). Если p является int *, а его значение является адресом 4-байтового объекта int (0x2000), p + 1 оценивает адрес следующего 4-байтового int объекта (0x2004).

  2. Как и другие типы, разные типы указателей могут иметь разные размеры и представления. int * может иметь представление, отличное от char *. На большинстве современных систем, таких как x86 и x86_64, они одинаковы, но есть некоторые старые или странные архитектуры, где это не так.

Таким образом, вывод можно объяснить, если предположить, что тип int имеет размер в один байт, почему printf сделал это вместо выдачи ошибки.

Проблема не в printf, а в том, что вы сталкиваетесь с целочисленным переполнением со знаком при попытке назначить 128 на *b, так как в вашей системе обычный char занимает диапазон [-128..127]. К сожалению, поведение при целочисленном переполнении со знаком равно undefined - не требуется, чтобы ваша реализация обрабатывала его каким-либо особым образом. Большинство реализаций, о которых я знаю, вообще не пытаются справиться с этим - вы просто получаете неожиданное значение. Учитывая, что существует несколько целочисленных представлений со знаком, и учитывая, что многие реализации полагаются на это неопределенное поведение для выполнения определенных оптимизаций, вы можете получить в значительной степени любой результат.

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