2017-01-19 18 views
1

Я столкнулся с следующей программой и не смог понять, как выход будет -109 1683. Как выйдет выход?Неоднозначный выход с использованием разыменования указателя?

#include <stdio.h> 

int main() 
{ 
int k = 1683; 
char *a = (char *)&k; 
int *l = &k; 
printf("%d " , *a); 
printf("%d" , *l); 
    } 
Output is : -109 1683 

Как разыменования указателя a дать мне -109?

Я ожидал, что он прочитает первый байт из четырех байтовых целых чисел.

1683 в двоичном представлении 00000000 00000000 00000110 10010011. Считывание первого байта означает, что вывод должен быть 0 1683. Что происходит за кулисами, я слышал что-то, что касалось архитектуры, но не мог следовать за ней.

+0

Thats из-за преобразования указателя на int для указателя на символ. Обратите внимание, что целое число равно 4 байтам, а char - 1-байтовая длина. – Gravell

+3

Что вы ожидали? – Stargateur

+0

Можете ли вы шаг за шагом объяснить мне, почему это происходит -109. –

ответ

1

Если у вас есть что-то подобное,

int k = 1683 ; 
int *l = &k; 

Если Вы разыменования указателя l, то он будет читать правильно целочисленные байты. Потому что вы объявили его указателем на int. Он будет знать, сколько байтов считывается оператором sizeof().Как правило, размер int является 4 bytes (для 32/64-битных платформ), но это зависит от машины, поэтому он будет использовать sizeof() оператору знать правильный размер и будет читать так .Теперь для кода

int k = 1683; 
char *a = &k; 
int *l = &k; 

Теперь pointer p указывает на y, но мы объявили его указателем на char, поэтому он будет читать только один байт или любой другой байтовый символ. 1683 в двоичной системе будет представлена ​​как

                00000000 00000000 00000110 10010011

Теперь, если ваша машина мало младшему будет хранить байты реверсирования их

                10010011 00000110 00000000 00000000

10010011 находится в address 00Hypothetical address, 00000110 находится в address 01 и так далее.

BE:  00 01 02 03 
     +----+----+----+----+ 
    y: | 00 | 00 | 06 | 93 | 
     +----+----+----+----+ 


LE:  00 01 02 03 
     +----+----+----+----+ 
    y: | 93 | 06 | 00 | 00 | 
     +----+----+----+----+ 

(In Hexadecimal) 

Так что теперь, если вы разыменования pointer a он будет читать только первый байт и выход будет -1, как прочитанный байт будет 10010011 (Потому что мы указали signed char, поэтому most-significant bit бит знака. Первый бит 1 означает знак 10010011 = –128 + 16 + 2 + 1 = –109.), И если вы разыскиваете pointer l, он полностью прочитает все байты int, так как мы объявили его указателем на int. И выход будет 1234

А также, если вы объявите указатель л, как int *l то *l прочтет sizeof(int) обычно 4 bytes (в зависимости от архитектуры машины) и *(l+1) также прочтет, что многие байт. То же самое происходит с char или любым другим типом данных, указатель, на который они указывают, будет считывать столько байтов, размер которых равен, char составляет 1 byte.

1

Типы «char» и «int» имеют разные размеры на большинстве платформ. В частности, «int» часто составляет 32 или 64 бита (4 или 8 байтов), а char - только 8 бит (1 байт). Когда вы ссылаетесь на «char», вы просите программу «интерпретировать» местоположение памяти вашего «int» как «char».

Кроме того, байты «int» хранятся в памяти либо в мини-эндианте, либо в формате big-endian (Google it). Таким образом, результаты вашей программы будут отличаться от платформы к платформе.

Если вы используете свой код на x86 (который является прямым порядком байт), то, возможно, увидеть «правильное» значение, если вы установите «Int» на значение меньше 128.

обновления : Как правильно указать, наименее значащий байт ИНТА является 10010011 который 147 десятичным и, таким образом, больше10000000 (128 десятичных). Поскольку самый старший бит байта установлен, значение интерпретируется как отрицательное значение дополнения 2 (Google it) от -109.

2

Отметьте, что 1683 = 0x693.

Если мы предположим, что:

  • Ваша архитектура HW является Little-Endian
  • Ваша платформа определяет CHAR_BIT в 8

Тогда в 0x693 первый char является 0x93.

На данный момент, обратите внимание, что:

  • В unsigned формате 2s-дополнение: 0x93 = 147
  • В signed формате 2s-комплемента: 0x93 = 147-256 = -109
0

Это происходит из-за того байта: https://en.wikipedia.org/wiki/Endianness

Фактически вы принимаете адрес байта 10010011, что составляет -109.

+0

Пожалуйста, напишите ответ и не указывайте ссылку, поскольку ссылки могут быть мертвы в любое время. –

6

Целое число 1683 равно 0x00000693 (int обычно составляет 32 бита на современных системах). На little-endian системе (например, x86 и x86-64) он выложил в памяти, как

 
+------+------+------+------+------+------+------+------+ 
| 0x93 | 0x06 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 
+------+------+------+------+------+------+------+------+ 

При инициализации указателя a вы делаете это указывает на первый байт в той последовательности, в которой байт содержит значение 0x93 , так что это значение, которое вы получаете при разыменовании a.

Так что теперь на вопрос о том, как значение 0x93 становится -109. Есть две причины: одна заключается в том, что char с вашим компилятором - signed (это зависит от компилятора, если char - это подписанный или неподписанный тип). Вторая причина связана с арифметикой two's complement. Two's complement - способ кодировать знаковые целые числа на двоичных машинах, таких как современные компьютеры.

В принципе, для одного 8-битного байта вы получаете отрицательное значение, считая (без знака) десятичное значение минус 256 (2). Беззнаковое десятичное значение 0x93 равно 147, а 147 - 256 равно -109.

2

int не менее 16 бит, в то время как char всегда 1 байт (not necessary 8-bit). Бинарная форма номера 1683 - 00000110 10010011. Поскольку вы используете char*, он будет указывать на первый байт. Но тогда что на первом месте? К какой из них относится char? 00000110 или 10010011? Это зависит от:

1) Если ваша система использует порядок байтов младшего порядка, она будет последней, которая равна 10010011.

00000110 10010011 
     ^^^^^^^^ 

Поскольку вы используете подписанchar типа, наиболее значащий байт будет использоваться как «знак-бит», то есть, если он равен 1, то байты представляют отрицательное число. Чтобы получить удобочитаемое значение aka base-10, вы делаете two-complement. Наконец, вы получите -109.

2) Если ваша система использует тупоконечник порядок байт, и он использует 16-битный int, это будет первое, что 00000110. Это легко, форма base-10 будет 6.

00000110 10010011 
^^^^^^^^ 

Если он использует 32-битную int, она будет равна нулю:

00000000 00000000 00000110 10010011 
^^^^^^^^ 
+0

@KeineLust 8-бит == 1 байт – raymai97

+1

На машинах большого конца с 32-битным 'int' результатом будет' 0', а не '6', это будет' 6' только с 16-битным 'int'. – mch

+0

@KeineLust oops ... мой плохой ... Я редактирую его ... – raymai97