C语言全局结构体变量存储及指针强制转换异常问题
C语言结构体存储与类型转换相关问题解答
1. C语言如何存储全局结构体变量?
- 全局结构体变量属于静态存储类别,分配在程序的静态存储区:
- 若被显式初始化,存在
.data段; - 若未初始化(或初始化为0),存在
.bss段。
- 若被显式初始化,存在
- 结构体内部成员按声明顺序依次存储,编译器会根据目标平台的内存对齐规则(比如按成员中最大基本类型的字节数对齐)插入填充字节,保证内存访问效率。
- 全局结构体的生命周期贯穿整个程序运行过程,作用域默认限于当前源文件,可通过
extern关键字扩展至其他文件。
2. 小结构体地址强制转换为大结构体指针后,c->b的内存地址是哪里?
先看给出的代码片段:
struct A{int a;}; struct B{int b;}; struct C{struct A a; struct B b;}; struct A aa; struct C * c = (struct C*) &aa;
从结构体布局规则分析:
struct C的起始地址与第一个成员a(struct A类型)的起始地址完全重合。struct A的大小为sizeof(int)(通常为4字节),默认对齐规则下,struct C中的b成员会紧跟在a成员的内存之后,因此c->b的地址是&aa + sizeof(struct A),也就是aa起始地址偏移4字节的位置。
但必须明确:这种写法属于未定义行为,因为aa的内存空间仅能容纳struct A,访问c->b本质是越界访问aa之外的内存,该区域的内容不确定,可能破坏其他变量或程序状态。
3. 测试代码中的行为是否符合预期?是否属于未定义行为?
先看测试代码:
#include <stdio.h> struct One{int a; int b;} s2,s1,*sp1; int e; int ff; struct Two{int c, d;} q,r,t, s4,s3; struct Three{struct One one; struct Two two;}; int main(){ e=1; sp1=&s1; sp1->a=1; s4.c=22; s3.c=10; struct Three * ll = (struct Three *) sp1; ll->two.c = 1000; printf("\n%d\t%d", s3.c, s4.c); return 0; }
- 这种行为完全不符合预期,且属于典型的未定义行为:
struct Three的大小为sizeof(struct One) + sizeof(struct Two)(通常为16字节),而s1是struct One类型,仅占8字节。将sp1(指向s1)强制转换为struct Three*后,访问ll->two.c属于越界访问s1内存之外的区域。- 编译器将
s1与s3放在相邻内存只是巧合,C标准不保证全局变量的存储顺序(仅保证同一结构体的成员顺序、同一源文件中相同存储类别的变量相对顺序)。修改ll->two.c不影响s3.c也是未定义行为的一种表现——越界访问的结果完全不可预测,可能修改到任意内存位置,也可能无可见影响,甚至导致程序崩溃。
内容的提问来源于stack exchange,提问作者lucifer
相关产品推荐
相关产品推荐

