Путаница с машинно-зависимыми значениями указателей

0

Я немного разбирался в указателях на C, и меня немного смутило немного кода, с которым я столкнулся. Я делал викторину на qeeksquiz.com/pointers для просмотра, и я наткнулся на этот фрагмент кода:

#include<stdio.h> 
int main() 
{ 
   int a; 
   char *x; 
   x = (char *) &a; 
   a = 512; 
   x[0] = 1; 
   x[1] = 2; 
   printf("%d\n",a);   
   return 0; 
}

Когда я столкнулся с x = (char *) &a я немного смутился. Я понимаю, что x является указателем, который содержит адрес a, но когда мы назначаем x[0] = 1 и x[1] = 2; ответ, когда печатается, составляет 513. В ответе говорится о том, как это зависит от того, какую машину мы используем, и о том, как машина little-endian меняет способ чтения в двоичном формате. Я полностью смущен тем, как мы получаем от 512 до 513. Я предполагаю, что это потому, что x [0] = 1, но я не уверен на 100%. Может кто-нибудь помочь объяснить это? Если бы мы назначили x[0] = 2, какова была бы величина изменения?

Спасибо за помощь!

Теги:
arrays
pointers
char

4 ответа

2

Искусство ASCII!

                   Little endian              Big endian

               +----+----+----+----+     +----+----+----+----+
a = 0x200:     | 00 | 02 | 00 | 00 |     | 00 | 00 | 02 | 00 |
               +----+----+----+----+     +----+----+----+----+

               +----+----+----+----+     +----+----+----+----+
x[0] = 1:      | 01 | 02 | 00 | 00 |     | 01 | 00 | 02 | 00 |
               +----+----+----+----+     +----+----+----+----+

               +----+----+----+----+     +----+----+----+----+
x[1] = 2:      | 01 | 02 | 00 | 00 |     | 01 | 02 | 02 | 00 |
               +----+----+----+----+     +----+----+----+----+

result:          1x1 + 2x256 = 513     1x16777216 + 1x65536 + 2x256 + 0x1 = big
2

поскольку x является указателем на char, это означает, что x [0] и x [1] относятся к однобайтовым данным, поэтому в вашей памяти у вас есть такие данные:

1 2

но во время вывода вы пытаетесь ссылаться на те же данные, что и 16/32 бит, поэтому у нас нет двух одиночных байтов, но 1 слово, которое хранится в памяти как 0x01 0x02, для маленького endian это означает, что мы должны поменять их, поэтому мы получаем число 0x201, которое равно 513 в десятичной нотации

для большого endian будет 0x102, что равно 258 в десятичной

  • 0
    Разве это не зависит от sizeof(int) ?
  • 0
    Это будет 258 только для 16-битного int . Для 32-битного int это будет 0x01020000
Показать ещё 1 комментарий
1

Целое число состоит из последовательности байтов. Но порядок байтов в разных системах различен. Например, рассмотрите номер 134480385 (двоичный = 00001000000001000000001000000001). В маленькой системе, это (с наименьшим адресом на LEFT)

00000001 00000010 00000100 00001000

Но в системе большого конца байты хранятся в обратном порядке. LEFT по-прежнему является самым низким адресом.

00001000 00000100 00000010 00000001

Когда вы берете адрес целого числа a и бросаете его в указатель char (byte), он указывает на первый байт в целочисленном (самый низкий адрес). Когда вы пишете 1 указателю, младший байт устанавливается на 00000001. Однако char имеет длину только 1 байт, поэтому остальные байты не изменяются. Затем второй байт устанавливается равным 00000010.

В вашем примере 512 в little endian

00000000 00000010

Большой endian более сложный, потому что результат зависит от количества байтов в int. Это обычно 4, но может быть 2 или более. В качестве 2-байтового int 512 в памяти

00000010 00000000

и как 4-байтовый int это

00000000 00000000 00000010 00000000

(Это не имеет значения для маленького endian, так как дополнительные байты - только нули)

После записи 1 в первый байт и 2 во второй байт вы получаете в памяти 4-байтовый маленький конец

00000001 00000010 00000000 00000000

4-байтовый большой endian

00000001 00000010 00000010 00000000

Обратите внимание, что бит в третьем байте все еще есть. Это связано с тем, что мы писали только первые два байта. Третий и четвертый байты не изменяются.

и 2-байтовый большой endian

00000001 00000010

Интерпретация 2 или 4-байтовой памяти (дополнительные нули игнорируются для 2-байтов) как малое число endian как нормальное двоичное число, это

00000000000000000000001000000001 = 513

Интерпретация 4-байтовой памяти как большого конечного числа как нормального двоичного числа

00000001000000100000001000000000 = 16908800

Интерпретация 2-байтной памяти как большого конечного числа как нормального двоичного числа

0000000100000010 = 258

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

0

Как указывали другие, трюк заключается в том, чтобы понять, как ints и символы представлены в памяти. Я написал код C++, который пытается показать вам именно это. Вставьте его в файл, скомпилируйте и запустите; затем измените значения в main и посмотрите, что произойдет. Здесь код:

#include <stdio.h>

// print one byte as a binary number
void print_binary(unsigned u) {
    for (int i = 7; i >= 0; --i)
        printf("%d", (u >> i) & 1);
}

// print a number binary representation
template <typename T>
void print_int_binary(T i) {
    char *cp = (char*)&i;
    for (int i = 0; i < sizeof(T); ++i) {
        print_binary(cp[i]);
        printf(" ");
    }
    printf("\n");
}

// show how the variable is represented in memory
template <typename T>
void print_var_binary(const char *name, T t) {
    printf("%s is stored as %d bytes:\n", name, (int)sizeof(t));
    print_int_binary(t);
}

#define PRINT(a) print_var_binary(#a, a);

int main() {
    PRINT((int)513)
    PRINT((char)2)
}

Когда я запускаю его на своем компьютере (little-endian), он печатает:

(int)513 is stored as 4 bytes:
00000001 00000010 00000000 00000000 
(char)2 is stored as 1 bytes:
00000010 

Ещё вопросы

Сообщество Overcoder
Наверх
Меню