C语言--复合类型、内存管理

一、复合类型(自定义类型)

1.1 共用体(联合体)

  • 共用体和结构体区别

    • 存储方式:

      • 结构体:结构体中的每个成员都占据独立的内存空间,成员之间按照定义的顺序依次存储

      • 共用体:共用体中的所有成员共享同一块内存空间,不同成员可以存储在同一个地址上

    • 内存占用:

      • 结构体:结构体的内存占用是成员变量占用空间之和,每个成员变量都有自己的内存地址

      • 共用体:共用体的内存占用是最大成员变量所占用的空间大小,不同成员变量共享同一块内存地址

              所谓的大端模式,是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
              所谓的小端模式,是指数据的低位保存在内存的低地址中,而数 据的高位保存在内存的高地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
      ​
      1)大端模式:
      ​
      低地址 -----------------> 高地址
      ​
      0x12  |  0x34  |  0x56  |  0x78
      ​
      2)小端模式:
      ​
      低地址 ------------------> 高地址
      ​
      0x78  |  0x56  |  0x34  |  0x12


 

#include <stdio.h>
#include <string.h>
union un
{
    char ch;
    int s;
    /* data */
}un;
​
​
int main() {
​
    un.s = 0x12345678;
    printf("%p\n", un.ch);
​
    if (un.ch == 0x78) {
        printf("小端对齐\n");
    }
    else {
        printf("大端对齐\n");
    }
    return 0;
}
​

1.2 枚举

  • 枚举:将变量的值一一列举出来,变量的值只限于列举出来的值的范围内

  • 语法格式:

    enum  枚举名 { 枚举值表 };
    • 在枚举值表中应列出所有可用值,也称为枚举元素

      • 枚举值是常量,不能在程序中用赋值语句再对它赋值

      • 枚举元素本身由系统定义了一个表示序号的数值从0开始顺序定义为0,1,2 …

 

 

1.3 typedef

  • typedef为C语言的关键字,作用是为一种数据类型(基本类型或自定义数据类型)定义一个新名字,不能创建新类型。

 

二、内存管理

2.1 C代码编译过程

  • 预处理

    • 宏定义展开、头文件展开、条件编译,这里并不会检查语法

  • 编译

    • 检查语法,将预处理后文件编译生成汇编文件

  • 汇编

    • 将汇编文件生成目标文件(二进制文件)

  • 链接

    • 将目标文件链接为可执行程序

    gcc -E hello.c -o hello.i //处理文件包含,宏和注释 
    gcc -S hello.i -o hello.s //编译为汇编文件 
    gcc -c hello.s -o hello.o //经汇编后为二进制的机器指令
    gcc hello.o -o hello      //链接所用的到库
    ​
    1 预处理:预处理相当于根据预处理命令组装成新的 C 程序,不过常以 i 为扩展 名。 
    2 编 译:将得到的 i 文件翻译成汇编代码 .s 文件。 
    3 汇 编:将汇编文件翻译成机器指令,并打包成可重定位目标程序的 O 文件。 该文件是二进制文件,字节编码是机器指令。 
    4 链 接:将引用的其他 O 文件并入到我们程序所在的 o 文件中,处理得到最终 的可执行文件

 

2.2 进程的内存分布

  • 程序运行起来(没有结束前)就是一个进程

  • 对于一个C语言程序而言,内存空间主要由五个部分组成 代码区(text)、数据区(data)、未初始化数据区(bss),堆(heap) 和 栈(stack) 组成

    • 有些人直接把data和bss合起来叫做静态区或全局区

img

  • 代码区(text segment)

    • 加载的是可执行文件代码段,所有的可执行代码都加载到代码区,这块内存是不可以在运行期间修改的。

  • 未初始化数据区(BSS)

    • 加载的是可执行文件BSS段,位置可以分开亦可以紧靠数据段,存储于数据段的数据(全局未初始化,静态未初始化数据)的生存周期为整个程序运行过程。

  • 全局初始化数据区/静态数据区(data segment)

    • 加载的是可执行文件数据段,存储于数据段(全局初始化,静态初始化数据,文字常量(只读))的数据的生存周期为整个程序运行过程。

  • 栈区(stack)

    • 栈是一种先进后出的内存结构,由编译器自动分配释放,存放函数的参数值、返回值、局部变量等。在程序运行过程中实时加载和释放,因此,局部变量的生存周期为申请到释放该段栈空间。

  • 堆区(heap)

    • 堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序。用于动态内存分配。堆在内存中位于BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。

2.3 堆区内存的使用

 

2.4 内存分布代码分析

2.4.1 返回栈区地址
address of stack memory associated with local variable 'a' returned [-Wreturn-stack-address]
​
这个警告意味着你的代码中有一个函数返回了指向本地变量的地址,而本地变量通常是分配在栈上的。这样做可能会导致未定义的行为,因为在函数调用结束后,本地变量的内存空间将被释放,指向它们的指针就会变成无效。
​
要解决这个警告,你需要确保函数返回的指针不指向本地变量,或者在函数内部动态分配内存,并返回分配的内存地址。如果你需要返回本地变量的值,可以通过函数参数传递给调用者,而不是返回指向本地变量的指针。

 

2.4.2 返回data区地址
  • 在函数内部使用static修饰的变量称为静态局部变量

  • 它在程序运行期间只被初始化一次,并且在函数调用结束后也不会被销毁

 

 

 

2.4.3 返回堆区地址


 

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值