柏虎资源网

专注编程学习,Python、Java、C++ 教程、案例及资源

c语言学习从内存堆栈视角,给这段共用体union代码做个 "内存透视"

从内存堆栈视角,给这段共用体代码做个 "内存透视"

#include <stdio.h>
#include <string.h>
 
union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main( )
{
   union Data data;        
 
   data.i = 10;
   data.f = 220.5;
   strcpy( data.str, "C Programming");
 
   printf( "data.i : %d\n", data.i);
   printf( "data.f : %f\n", data.f);
   printf( "data.str : %s\n", data.str);
 
   return 0;
}

咱们先打个比方:共用体(union)就像一个 "多功能储物盒"—— 盒子只有一个,但可以放不同类型的东西(整数、浮点数、字符串),但每次只能放一种,新东西放进去会把旧的覆盖掉。而栈就像家里的临时置物台,这个盒子用完就收走,不占地方。

先看懂代码的 "迷惑行为"

这段代码定义了一个Data共用体,里面可以放整数i、浮点数f或字符串str。然后在main里创建了data变量,先存 10,再存 220.5,最后存字符串 "C Programming",然后打印这三个值。运行结果会很奇怪:

plaintext

data.i : 1917853767
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

整数和浮点数都乱了,只有字符串正常。这不是 bug,而是共用体的特性!今天咱们就从内存角度扒开这个 "多功能盒子" 的秘密。

内存区域聚焦:栈是唯一舞台

C 程序内存的三大块里,这段代码只用到了栈:



  • 栈(Stack):像临时置物台,main函数运行时在这里给共用体变量分配空间,函数结束后自动释放。
  • 全局区和堆:这段代码没用到,暂时忽略。

逐行拆解:共用体在栈上的 "覆盖术"

1. 共用体定义:设计 "多功能盒子图纸"

c

运行

union Data {
   int i;          // 整数(4字节)
   float f;        // 浮点数(4字节)
   char str[20];   // 字符串(20字节)
};



  • 这是共用体的 "设计图纸",告诉编译器:这个盒子能放三种东西,但整个盒子的大小由最大的成员决定(这里str[20]最大,所以盒子总大小是 20 字节)。
  • 重点:图纸不占运行时内存,就像你画的 "多功能盒子" 设计图不会占地方。

2. 创建共用体变量:栈上分配 "20 字节盒子"

c

运行

int main() {
   union Data data;  // 共用体变量
   // ...
}



  • 程序运行时,main函数的栈帧在上创建,给data分配了 20 字节的连续空间(因为str[20]是最大成员)。这个空间就是那个 "多功能盒子",所有成员都共用这 20 字节 —— 就像一个盒子,既可以当 4 字节的小格子用(存i或f),也可以当 20 字节的长格子用(存str)。
  • 栈帧里的data初始布局(20 字节,地址连续):
  • plaintext
┌─────────────────────────────────────┐
│ 字节0 字节1 字节2 ... 字节19        │  ← 共20字节,初始值是栈上的随机垃圾
└─────────────────────────────────────┘

3. 给共用体赋值:"新内容覆盖旧内容"

c

运行

data.i = 10;         // 第一步:存整数10
data.f = 220.5;      // 第二步:存浮点数220.5(覆盖前面的10)
strcpy(data.str, "C Programming");  // 第三步:存字符串(覆盖前面的220.5)



  • 第一步:存i=10
    整数i占 4 字节,往盒子的前 4 字节(字节 0-3)存入 10 的二进制(00000000 00000000 00000000 00001010)。此时字节 4-19 还是随机值。
  • 第二步:存f=220.5
    浮点数f也占 4 字节,会
    覆盖前 4 字节,存入 220.5 的二进制(浮点数有特殊编码规则)。此时前 4 字节已经不是 10 了,后面 16 字节还是随机值。
  • 第三步:存字符串"C Programming"
    字符串str占 20 字节,会从字节 0 开始逐个存入字符:'C',' ','P','r','o','g','r','a','m','m','i','n','g','\0'(共 14 个字符),剩下的字节 6-19 被填充 '\0'。这一步会
    覆盖整个 20 字节,包括前 4 字节 —— 所以之前存的i和f全被冲掉了!

4. 打印结果:"读的是同一块内存,但解析方式不同"

c

运行

printf("data.i : %d\n", data.i);   // 读前4字节,按整数解析
printf("data.f : %f\n", data.f);   // 读前4字节,按浮点数解析
printf("data.str : %s\n", data.str); // 读20字节,按字符串解析



  • 打印data.i:读前 4 字节(现在是 'C',' ','P','r' 的 ASCII 码),强行按整数规则解析,得到一个乱码数字(1917853767)。
  • 打印data.f:读前 4 字节,强行按浮点数规则解析,结果更离谱(因为这 4 字节本来是字符,不是浮点数编码)。
  • 打印data.str:读整个 20 字节,按字符串规则解析(直到 '\0'),所以正常显示 "C Programming"。
  • 就像你用收音机听 CD:CD 里存的是音乐(字符串),但你非要用收音机的方式(整数 / 浮点数解析)听,出来的只能是噪音。

5. 程序结束:栈帧 "整体清空"

c

运行

return 0;



  • main函数结束,栈帧被释放,data的 20 字节空间被回收(临时置物台上的盒子被收走)。

共用体的内存本质:"一块内存,多种解读"

  • 大小由最大成员决定:不管存什么,共用体变量的大小永远等于最大成员的大小(这里 20 字节)。
  • 成员共享同一块内存:新成员赋值会覆盖旧成员(因为地址重叠),所以同一时间只能用一个成员。
  • 解析方式决定值:同一块内存,按不同类型解析(整数 / 浮点数 / 字符串)会得到不同结果,就像同样的二进制,用 txt 打开是文字,用 jpg 打开可能是乱图。

关键结论:共用体是 "内存里的多面镜"

  • 共用体变量data在栈上占 20 字节,所有成员都共享这 20 字节 —— 这是和结构体最本质的区别(结构体成员各占空间,不重叠)。
  • 它的价值是 "节省内存":当你知道某块内存同一时间只会存一种类型时,用共用体比结构体更省空间(比如 20 字节 vs 28 字节(4+4+20))。
  • 但要小心 "覆盖陷阱":存新值会冲掉旧值,所以使用时必须清楚当前存的是什么类型,否则会读错数据(就像你得知道盒子里现在放的是饼干还是手机,否则可能会一口咬下去)。
#include <stdio.h>
#include <string.h>
 
union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main( )
{
   union Data data;        
 
   printf( "Memory size occupied by data : %d\n", sizeof(data));
 
   return 0;
}
#include <stdio.h>
#include <string.h>
 
union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main( )
{
   union Data data;        
 
   data.i = 10;
   printf( "data.i : %d\n", data.i);
   
   data.f = 220.5;
   printf( "data.f : %f\n", data.f);
   
   strcpy( data.str, "C Programming");
   printf( "data.str : %s\n", data.str);
 
   return 0;
}

标题:

  1. 《C 语言共用体:栈上的 "多功能盒子",存新值会覆盖旧值》
  2. 《从内存看共用体:同一块空间,多种解读方式的 "魔术"》

简介:

通过分析共用体代码的内存分配,揭示共用体成员共享同一块内存(大小由最大成员决定)、新值覆盖旧值的特性,解析打印结果混乱的原因,展现共用体节省内存但需注意类型匹配的特点。

关键词:

#C 语言共用体 #栈内存 #内存共享 #类型解析 #内存覆盖

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言