C语言中使用memset将内存置0的不可移植场景有哪些?
问题核心原因
首先要明确,memset做的是字节层面的全0填充,而{0}做的是C语言语义层面的零值初始化,两者的行为在部分特殊架构下并不等价,这就是memset写法不可移植的根本原因。
C标准明确规定:{0}初始化会将对象的所有成员递归设置为对应类型的零值,这个零值是语义层面的:
- 对整数类型就是
0 - 对指针类型就是空指针
NULL - 对浮点类型就是
0.0
无论这些值在底层的字节表示是什么样的,编译器都会自动处理成正确的格式。
而memset(&x, 0, sizeof x)只会把x占据的所有内存字节全部设置为0x00,这只在「语义零值的字节表示恰好是全0」的平台上和{0}等价。
不可移植的具体场景
- 空指针表示不是全0的平台:C标准没有要求空指针
NULL的底层字节必须是全0,部分老旧的特殊架构(比如部分嵌入式、大型机架构)上空指针的二进制表示是其他值。如果初始化的对象(或者其内部成员)是指针类型,memset得到的就不是合法的空指针,会引发未定义行为。 - 浮点零表示不是全0的平台:C标准也没有强制要求浮点数必须用IEEE754标准,部分特殊架构上浮点数
0.0的底层字节不是全0,此时memset填充的内存就不是正确的浮点零值。 - 实现定义的不透明类型初始化:类似
mbstate_t、pthread_mutex_t这类标准库定义的不透明类型,你无法预知其内部成员结构,很可能内部包含指针、浮点类型,或者其合法的零状态本身就不是全字节0,此时用memset初始化必然不符合可移植要求。
补充说明
目前我们常用的x86、ARM、RISC-V等主流平台,空指针都是全0表示,浮点数也都遵循IEEE754标准(零值为全0),所以绝大多数场景下memset写法都能正常运行,这也是很多人感知不到可移植性问题的原因。但如果你的代码需要严格符合C标准、要求能在所有符合标准的架构上运行,就应该使用{0}做通用零初始化,而不是memset。
内容的提问来源于stack exchange,提问作者Felix Dombek
相关产品推荐
相关产品推荐

