>> >> >> Reference << << << <<<<<<Ref>>>>>>
Object Model
Modified: 2025-12-31 | Author:ljf12825

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

Object

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

关键点:

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

对象是存储,不是值

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

int x = 10;

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

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

对象必须存在一段时间

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

void f() {
    int x; 
}

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

对比

# define N 10 

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

对象 =/ 变量

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

int x; 
malloc(sizeof(int));
struct S {
    int a;
    int b;
};

对象是层级结构的

字符串字面量也是对象

"hello"

这是一个

这解释了为什么

char *p = "hello";

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

对象的三大支柱

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

1. 存储期(Storage Duration)

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

四种存储期

1. 自动存储期

void f() {
    int x;
}

2. 静态存储期

static int x;
int g;

3. 动态存储期

int *p = malloc(sizeof *p);

4. 线程存储期(C11)

_Thread_local int x;

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

类型(Type)

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

int x

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

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

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

int x;
int *p = &x;

这就是strict aliasing的根源

子对象模型

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

数组对象

int a[4];

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

结构体对象

struct S {
    int a;
    char b;
};

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 的所有规则都围绕对象展开

没有对象模型,就不可能

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