Выяснение адресов в C [закрыто]


Я пытаюсь узнать, как вычислить адреса в C. Для кода ниже, предполагая, что он скомпилирован на 32-битной маленькой машине endian.

struct {
    int n;
    char c;
} A[10][10];

Скажем, адрес A[0] [0] равен 1000 (десятичный), каким будет адрес A[3][7]? Любая помощь ценится!

5 3

5 ответов:

C являетсяупорядоченным по строкам , что означает, что сначала вычисляется самый левый индекс. Таким образом:

&A[3] == 1000 + (3 * 10 * sizeof(your_struct))

Чтобы найти столбец, мы просто добавляем оставшийся индекс:

&A[3][7] == 1000 + (3 * 10 * sizeof(your_struct)) + (7 * sizeof(your_struct))

Обратите внимание, что это не имеет ничего общего с архитектурой big-endian vs little-endian. Это просто расположение байтов в слове, в то время как вы хотите расположение структур в массиве.

Кроме того, sizeof(your_struct) не гарантированно будет sizeof(n) + sizeof(c), потому что компилятор может дополнить ваш структура.

Наконец, 32-битная природа вашей машины означает, что размер регистра адреса памяти равен 32 битам. (Или, говоря по-другому, sizeof(void*)==32). Это показатель того, сколько памяти ваш процессор может на самом деле назначить адрес. Это отдельная проблема от размера типов данных в C.

Это зависит не от стандарта языка Си, а от компилятора, версии компилятора и ОС, которую вы используете/targeting.

Единственный способ получить результат для вашего конкретного случая-это проверить его вручную.

Это наверняка зависит от компилятора и системы. Но нет нужды гадать. Вы можете просто скомпилировать и попробовать

#include <stdio.h>

int main()
{
    struct {
        int n;
        char c;
    } A[10][10];

    printf("%08x\n", &A[0][0]);
    printf("%08x\n", &A[0][1]);
    printf("%08x\n", &A[1][0]);
    ...
    printf("%08x\n", &A[3][7]);

    ...
}

Нотация массива-это просто сокращение для вычисления адреса элемента и разыменования его, например:

int a[5][15];
Address of a[3][7]: &a + 3 * 15 * sizeof(int) + 7 * sizeof(int)
Вот почему вы не можете использовать n-мерный массив, не зная всего, кроме последнего измерения - компилятор не будет знать, какое смещение добавить к нему, чтобы вычислить адрес.

В этом случае дело осложняется тем, что вы используете структуру. Существует проблема выравнивания, когда структуры дополняются компилятором для выравнивания по слову границы. В этом случае, поскольку сама структура занимает 5 байт, а следующая граница слова будет равна 8 байтам, компилятор, вероятно, добавит 3 неиспользуемых байта к структуре, чтобы компенсировать разницу. (Есть преимущества в производительности, чтобы делать так.) Конечно, это не гарантируется вообще, и вы можете вручную указать, как компилятор должен обрабатывать такие ситуации.

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

Она полностью зависит от системы, а не от языка .

Также все 2-D , 3-D и так далее массивы фактически распределяются последовательным образом,потому что память является последовательной (0X00000000 to 0xFFFFFFFF) Такой 2-D памяти нет или около того .

Это полностью зависит от системы, как распределяется память, является ли она row Главной или column главной

Формула для строки major:

&A[3][7] == &A[0][0] + (3 * 10 * sizeof(struct s)) + (7 * sizeof(struct s))

Для главной колонки:

&A[3][7] == &A[0][0] + (7 * 10 * sizeof(struct s)) + (3 * sizeof(struct s))

И компилятор оптимизировать его структуру заполнения более быстрый доступ по процессору.

Таким образом, для одного объекта размер структуры будет 8, а не 5 (если int имеет размер 4 байта)