struct thing {
int x;
thing* next;
}
显然,大小是sizeof(int)+sizeof(thing*)
,但是sizeof(thing*)
是什么?好吧,它是指向一个结构的指针的大小,该结构包含一个int加上指向另一个结构的指针的大小,该结构包含一个int和一个指向另一个结构的指针,该结构的大小为....... .........
所以我觉得事物的大小必须是无限的。 (当数学专业的学生拿起一本编程书时会发生这种情况。他把所有东西都带到了它的逻辑极端而感到困惑。)
答案 0 :(得分:2)
请注意,您引用的thing *
与struct thing
100%无关。这是C;你的标签是这样说的。您可以编写此代码以使代码编译干净:
typedef struct thing thing;
struct thing
{
int x;
thing *next;
};
struct thing
的最小尺寸为sizeof(int) + sizeof(thing *)
,但结构可能大于sizeof(int)
。实际上,在我的(64位)机器上,结构的大小为16字节,即使int
只是4.这是因为地址必须是8字节对齐,所以{之间有4个字节的填充{1}}和指针。
你能解释一下“8字节对齐”是什么意思吗?
许多CPU要求N字节基本类型应存储在N的倍数地址。因此,1字节char
变量可以存储在任何地址,但是2字节{ {1}}变量必须存储在2的倍数地址,4字节short
变量必须存储在4的倍数地址等。对于某些机器,尤其是RISC架构,如果你试图读取错误的对齐,你会得到一个SIGBUS信号(和核心转储)。对于其他人来说,你最终会让CPU进行多次读取和钻头纠缠以获得正确的结果,但比数据正确对齐要慢得多。编译器知道这些都很昂贵,并确保它们不违反规则。并且编译器在必要时将结构填充到结构中,除了结构的开头,以确保结构中的元素正确对齐,并且结构类型的数组元素将正确对齐。
考虑一个64位编译器和数据结构:
int
即使单个struct list
{
struct list *next;
int data;
};
可能只有12个字节(指针为8个字节,数据为4个字节),编译器会在末尾添加4个字节的填充,这样如果你有一个数组这些结构,数组中第二项的起始地址将在8个字节的倍数上正确对齐(需要因为地址是64位,8字节数量)。
显然,sizeof(int)+ sizeof(thing *),但sizeof(thing *)是什么?好吧,它是一个指向结构的指针的大小,该结构包含一个int加上指向另一个结构的指针的大小,该结构包含一个int和一个指向另一个结构的指针,该结构的大小为........... .....
所以我想事情的大小必须是无限的。
这里没有无限的退步。结构的大小和指向结构的指针的大小是两个非常不同的东西。 C不允许递归类型:
struct list
这需要无限量的内存,甚至虚拟内存都无法模拟(计算机主内存中没有足够的位来保存无限大的数据结构的大小,更不用说无限大的结构本身了)。
但问题中的结构不包含结构;它包含一个指向结构的指针。 C标准保证结构的所有地址都是相同的大小(POSIX提出了更严格的要求 - 所有指向所有对象的指针和指向函数的指针必须具有相同的大小)。因此,指向结构的指针的大小是固定的 - 对于32位编译为4个字节,对于64位编译为8个字节(实际上,即使理论上可能存在例外)。并且结构的大小是固定且有限的。
答案 1 :(得分:1)
不,不,不,sizeof(struct thing*)
只是指向结构所需指针的大小,不可能在结构中的任何东西。 (例如,考虑空指针的情况。)
答案 2 :(得分:1)
不,指针的大小固定。所以thing的大小是sizeof(int)+ sizeof(指针)。
Nitpicker的角落:
通常遇到的CPU架构中指针的大小为4或8个字节,具体取决于CPU架构。
然而,一些不常见的架构(DSP芯片,奇怪的微控制器,PDP-10和其他面向字的架构)具有不同大小的指针。
此外,在一些不常见的体系结构中,指向不同大小的对象的指针本身具有不同的大小,因此,例如,sizeof(char *)!= sizeof(int *)。
此外,某些体系结构允许面向位的寻址,因此可以获取位域的地址,这通常是不允许的。 (C标准不允许这样做,但可以作为供应商扩展来完成。)
答案 3 :(得分:1)
指针的大小不依赖于指针到的指针。指针将是一个单词的大小,因此系统可以是4或8个字节。