Приведение int указатель на char указатель приводит к потере данных в C? - PullRequest
4 голосов
/ 06 марта 2011

У меня есть следующий фрагмент кода:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
  int n = 260; 
  int *p = &n;
  char *pp = (char*)p;
  *pp = 0;

  printf("n = %d\n", n);
  system("PAUSE");  
  return 0;
}

Выход программы: n = 256.Я могу понять, почему это так, но я не совсем уверен.Кто-нибудь может дать мне четкое объяснение, пожалуйста?

Большое спасибо.

Ответы [ 7 ]

11 голосов
/ 06 марта 2011

int 260 (= 256 * 1 + 4) будет выглядеть так в памяти - обратите внимание, что это зависит от порядка байтов машины - также это для 32-битной ( 4 байта) int:

0x04 0x01 0x00 0x00

Используя указатель char, вы указываете на первый байт и меняете его на 0x00, что заменяет int на 256 (= 256 * 1 + 0).

3 голосов
/ 06 марта 2011

Вы очевидно работаете на машине с прямым порядком байтов. Происходит то, что вы начинаете с int, который занимает как минимум два байта. Значение 260 составляет 256 + 4. 256 идет во втором байте, а 4 в первом байте. Когда вы записываете 0 в первый байт, у вас остается только 256 во втором байте.

1 голос
/ 06 марта 2011

В C указатель ссылается на блок байтов на основе типа, связанного с указателем.Так что в вашем случае целочисленный указатель относится к блоку размером 4 байта, в то время как длина символа составляет всего один байт.Когда вы устанавливаете char в 0, он изменяет только первый байт целочисленного значения, но из-за того, как числа хранятся в памяти на современных машинах (фактически в обратном порядке по сравнению с тем, как вы его записали), вы перезаписываете младший байт (который был 4) вы остались с 256 в качестве значения

1 голос
/ 06 марта 2011

Я понял, что именно происходит, изменив значение:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
  int n = 260; 
  int *p = &n;
  char *pp = (char*)p;
  *pp = 20;

    printf("pp = %d\n", (int)*pp);
  printf("n = %d\n", (int)n);
  system("PAUSE");  
  return 0;
}

Выходное значение 20 а также 276

Таким образом, в основном проблема не в том, что у вас потеря данных, а в том, что указатель на символ указывает только на первый байт целого и поэтому он меняет только то, что остальные байты не изменяются, и поэтому эти странные значения вы используете процессор INTEL, первый байт является наименее значимым, поэтому вы меняете «наименьшую» часть числа

0 голосов
/ 13 сентября 2016

Учитывая 32-битные системы, 256 будет представлен следующим образом.

00000000 (Byte-3)   00000000 (Byte-2)    00000001(Byte-1)     00000100(Byte-0)

Теперь, когда p приведен к типу указателя на символ, метка на указателе изменяется, а содержимое памяти - нет. Это означает, что раньше p мог иметь доступ 4 байта, так как это был целочисленный указатель, но теперь он может получить доступ только к 1 байту, так как это указатель на символ. Таким образом, только LSB получает изменения в ноль, а не все 4 байта.

И становится

00000000 (Byte-3)   00000000 (Byte-2)    00000001(Byte-1)     00000000(Byte-0)

Следовательно, o / p равно 256.

0 голосов
/ 24 апреля 2011

С точки зрения языка C, описание того, что вы делаете, это изменение представления переменной int n. В C все типы имеют «представление» в виде одного или нескольких байтов (unsigned char), и доступ к базовому представлению разрешен путем приведения указателя к char * или unsigned char * - последний лучше по причинам, которые могли бы просто излишне усложняйте вещи, если я зайду в них здесь.

Как ответил schnaader, в порядке с прямым порядком байтов, дополняющем реализацию с 32-битным int, представление 260:

0x04 0x01 0x00 0x00

и перезапись первого байта с 0 приводит к:

0x00 0x01 0x00 0x00

что представляет собой представление 256 для такой реализации.

C позволяет реализациям, которые имеют биты заполнения и представления прерываний (которые вызывают сигнал / отменяют вашу программу, если к ним обращаются), поэтому в общем случае перезаписать часть, но не всю int, таким образом, небезопасно , Тем не менее, он работает на большинстве реальных машин, и если вместо этого вы используете тип uint32_t, он будет гарантированно работать (хотя порядок битов все равно будет зависеть от реализации).

0 голосов
/ 06 марта 2011

Ваша проблема в задании * pp = 0; Вы разыменовываете pp, который указывает на n, и меняете n. Тем не менее, pp является указателем на символ, поэтому он не меняет все n который является инт. Это вызывает двоичные осложнения в других ответах.

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