在C语言中理解地址

3

我正在尝试学习如何在C语言中找出地址。对于下面的代码,假设它在一个32位小端机器上编译。

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

假设A[0][0]的地址为1000(十进制),那么A[3][7]的地址是多少呢?感谢您的帮助!


1
你肯定是指 &A[0][0] ... - leppie
你应该在实际的程序中尝试一下。细节取决于编译器、操作系统、ABI和指令集。你可能需要使用offsetof__alignof__sizeof与GCC。 - Basile Starynkevitch
1
为什么不编译它,打印地址,然后弄清编译器如何排列事物呢? - John3136
1
希望这个链接可以帮助你理解:http://www.cs.sunysb.edu/~skiena/214/lectures/lect20/lect20.html - Bhavik Shah
我更感兴趣的是从概念层面上找到地址,上面的程序只是我尝试学习的具体示例。 - Joe Crawley
1
最有可能的情况是,结构体会被填充到最大使用数据类型的类型边界。在这里,它是int,因此A的一个条目的sizeof将为8字节。即sizeof(A [0] [0])将为8。从起始地址开始进行计算。 - fkl
5个回答

8

C语言是按行主序排列的,这意味着最左边的索引首先计算。因此:

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

要找到这一列,我们只需将剩余的索引相加:

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

请注意,这与大端和小端架构无关。那只是字节在一个字中的位置,而您想要的是结构在数组中的位置。
另外,`sizeof(your_struct)`不能保证是`sizeof(n) + sizeof(c)`,因为编译器可能会填充您的结构。
最后,您的计算机的32位特性意味着内存地址寄存器的大小为32位。 (或者换句话说,`sizeof(void*)==32`)。这表明您的处理器实际上可以分配地址的内存量。这是C语言数据类型大小的另一个问题。

2

这不仅取决于C语言标准,还取决于编译器、编译器版本和您使用/定位的操作系统。

获取您特定情况的结果的唯一方法是手动测试。


1

数组表示法只是一种简写方式,用于计算元素的地址并对其进行取消引用,如下所示:

int a[5][15];
Address of a[3][7]: &a + 3 * 15 * sizeof(int) + 7 * sizeof(int)

这就是为什么在不知道除了最后一个维度之外的所有维度的情况下不能使用n维数组 - 编译器将不知道要添加什么偏移量才能计算地址。

在这种情况下,由于您正在使用结构体,问题变得更加复杂。存在对齐问题,编译器会填充结构体以对齐到字边界。在这种情况下,由于结构体本身占用5个字节,而下一个字边界将在8个字节处,编译器很可能会向结构体添加3个未使用的字节来弥补差距。(这样做有性能优势。)当然,这并不是完全保证的,您可以手动指定编译器应如何处理这种情况。

注意:正如其他人所说,这非常依赖于系统和编译器,因此不要将其中任何内容视为绝对真实 - 请自行尝试以确保在您的情况下结果将是什么。


当然,你是正确的 - 不知为何我在想列优先。谢谢,我现在会更新。 - Chris Hayes

1

这肯定是与编译器和系统有关。但无需猜测,您可以直接编译并尝试。

#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]);

    ...
}

0

它完全依赖于系统而不是语言。

此外,所有的2-D、3-D等数组实际上都是按顺序分配的,因为内存是顺序的(0X00000000到0xFFFFFFFF)没有这样的2-D内存等。

它完全依赖于系统如何分配内存,无论是按行主还是按列主。

行主公式:

&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))

编译器还通过结构填充进行优化,以便CPU更快地访问。

因此,对于一个结构体对象,其大小将为8而不是5(如果int的大小为4个字节)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接