>> >> >> Reference << << << <<<<<<Ref>>>>>>
>> >> >> Indexer << << << <<<<<<Idx>>>>>>
Matched: 0

Tags

    Categories

      Types

        Top Results

          Object Model
          M: 2025-12-31 - ljf12825

          对象模型是:C 语言如何在“抽象定义”与“真实机器内存”之间建立对应关系
          换句话说:C 如何描述“一段内存,在什么时候,能被谁、以什么方式访问
          这套描述,就是C 的对象模型

          Object

          在C 的语义中:对象 = 在程序执行期间存在的一段存储区域,其内容可以表示一个值

          关键点:

          • 执行期间 -> 生命周期
          • 存储区域 -> 有地址、有大小
          • 表示一个值 -> 必须能被类型解释

          因此,没有存储期的东西,不是对象;不能被类型解释的东西,不是对象

          对象是存储,不是值

          对象不是数值、不是类型、不是名字

          int x = 10;
          
          • x:标识符(名字)
          • int:类型(解释规则)
          • 对象:一段内存(通常4字节)

          对象只是那4个字节本身,10只是这4个字节在int规则下被解释出来的结果

          换句话说,对象 = 内存;值 = 内存 + 类型解释

          对象必须存在一段时间

          对象一定有存储期(storage duration)

          void f() {
              int x; 
          }
          
          • 进入函数 -> x的对象出现
          • 离开函数 -> 对象消失

          这就是”对象存在“的时间窗口

          对比

          # define N 10 
          

          N没有对象,它从来没有”存在于内存中“

          对象 =/ 变量

          变量 = 具名对象
          对象 =/ 一定有名字

          int x; 
          
          • 有对象,有名字 -> 变量
          malloc(sizeof(int));
          
          • 有对象,没有名字;只能通过指针访问它
          struct S {
              int a;
              int b;
          };
          
          • struct S本身不是对象
          • a, b是子对象(subobject)

          对象是层级结构的

          字符串字面量也是对象

          "hello"
          

          这是一个

          • char[6]对象
          • 静态存储期
          • 没有名字
          • 不能修改(修改是UB)

          这解释了为什么

          char *p = "hello";
          

          拿到的是指向一个对象的指针,不是“字符串本身”

          对象的三大支柱

          C 的对象模型完全由这三件事支撑

          1. 存储期(Storage Duration)

          对象在什么时候存在,这是第一性问题

          四种存储期

          1. 自动存储期

          void f() {
              int x;
          }
          
          • 进入作用域 -> 对象出现
          • 离开作用域 -> 对象消失
          • 通常在栈上

          2. 静态存储期

          static int x;
          int g;
          
          • 程序启动前分配
          • 程序结束时销毁
          • .data/ .bss/ .rodata

          3. 动态存储期

          int *p = malloc(sizeof *p);
          
          • 运行期创建
          • free之前一直存在
          • 生命周期不依赖作用域

          4. 线程存储期(C11)

          _Thread_local int x;
          
          • 每个线程一份对象
          • 生命周期 = 线程

          存储期决定:对象“在不在”

          类型(Type)

          对象本身只是比特,类型是解释规则,决定

          • 对象占多大空间
          • 对齐要求
          • 读写方式
          • 运算规则
          • 是否允许别名
          int x
          
          • 对象:4字节(假设)
          • 类型:int
          • “10"只是解释结果,不是对象的一部分

          类型不是对象的属性,而是访问对象时使用的规则。同一对象,用不同类型访问 -> UB或不同语义

          标识与访问路径(Name/Lvalue)

          对象可能有名字,没名字,有多个访问路径

          int x;
          int *p = &x;
          
          • 一个对象
          • 两条访问路径
          • x*p必须遵守类型系统一致性

          这就是strict aliasing的根源

          子对象模型

          C的对象不是扁平的,是分层结构

          数组对象

          int a[4];
          
          • 一个数组对象
          • 包含4个int子对象
          • 内存连续

          数组不是“指针集合”,是一个整体对象

          结构体对象

          struct S {
              int a;
              char b;
          };
          
          • 一个 struct 对象
          • 两个成员子对象
          • 中间可能有padding(也是对象的一部分)

          padding属于对象,但不属于任何子对象

          联合体对象(union)

          union U {
              int i;
              float f;
          };
          
          • 一个对象
          • 多个成员重叠
          • 一次只能有一个“有效成员”

          对象可以嵌套,但规则仍是:一段内存 + 存在时间

          对象 vs 表达式

          x + 1
          

          这不是对象

          • 没有地址
          • 没有存储期
          • 只是一个临时计算结果

          即使编译器真的用寄存器存了它,在语言语义上,它仍然不是对象

          对象是语言层面的概念,不是”有没有寄存器“

          对象与生命周期规则

          几乎所有 C 的未定义行为,都来自对象模型被破坏

          生命周期结束后访问

          int *p;
          {
              int x = 10;
              p = &x;
          }
          *p = 20; // UB
          

          对象已不存在

          越界访问

          int a[4];
          a[4] = 1; // UB 
          

          对象模型之外

          非法类型访问

          int x;
          float *p = (float*)&x;
          *p = 1.0f; // UB (严格别名)
          

          违反对象的“有效类型”

          malloc 的特殊地位

          void *p = malloc(16); 
          

          此时:

          • 对象存在
          • 没有有效类型

          第一次通过某种类型访问它

          int *q = p;
          *q = 10;
          

          此时,对象的有效类型变为int
          malloc 返回的是“未定型对象”


          C 的对象模型实际上是程序员、编译器、硬件之间的三方契约

          C 故意不等同于真实硬件

          • 程序员视角:逻辑对象,有生命周期和类型语义
          • 编译器视角:优化许可,可重排、可消除、可别名分析
          • 硬件视角:最终映射,寄存器、内存、缓存的实际使用

          这种分离正是C即能在高层抽象又能在底层操作的核心机制

          C 的所有规则都围绕对象展开

          没有对象模型,就不可能

          • 定义 UB
          • 允许 aggressive optimization
          • 做别名分析
          • 做栈/堆抽象
          • 写可移植的底层代码

          在C 语言里,没有对象,就没有未定义行为;没有未定义行为,就没有 C