1e41f4b71Sopenharmony_ci# OpenHarmony 32/64位可移植编程规范 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## 前言 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci### 目的 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciOpenHarmony的目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。具有“硬件互助,资源共享”、“一次开发,多端部署”、“统一OS,弹性部署”的技术特性。 8e41f4b71Sopenharmony_ciOpenHarmony支持三种系统类型: 9e41f4b71Sopenharmony_ci 10e41f4b71Sopenharmony_ci1. 轻量系统(mini system),面向MCU类处理器(例如Arm Cortex-M、RISC-V 32位)的轻量设备,硬件资源极其有限,支持的设备最小内存为128KiB 11e41f4b71Sopenharmony_ci2. 小型系统(small system),面向应用处理器(例如Arm Cortex-A 64位)的设备,支持的设备最小内存为1MiB 12e41f4b71Sopenharmony_ci3. 标准系统(standard system),面向应用处理器(例如Arm Cortex-A 64位)的设备,支持的设备最小内存为128MiB 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ci因此,OpenHarmony的代码运行在32位/64位的设备上。对系统代码的可移植性、32位/64位运行模式下的编码需要一定的规约。本文以此为初衷,结合OpenHarmony的特点,拟定了相关编程规约,用于指导代码移植和64位编码,提升代码的规范性及可移植能力,供研发人员参考。 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ci### 适用范围 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ci用户态和内核态的C、C++代码,不区分语言的标准。 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci### 32位/64位系统的类型差异 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ci#### 数据类型差异 23e41f4b71Sopenharmony_ci 24e41f4b71Sopenharmony_ci大部分的32位系统采用的是ILP32,即int、long和pointer是32位长度。大部分的64位系统采用的是LP64,即long、long long、pointer是64位长度。Windows系统采用的是LLP64,即long long和pointer是64位长度。各系统基本数据类型长度对比如下表所示: 25e41f4b71Sopenharmony_ci 26e41f4b71Sopenharmony_ci| **TYPE** | **ILP32** | **LP64** | **LLP64** | **LP32** | **ILP64** | 27e41f4b71Sopenharmony_ci| --------- | --------- | -------- | --------- | -------- | --------- | 28e41f4b71Sopenharmony_ci| char | 1 | 1 | 1 | 1 | 1 | 29e41f4b71Sopenharmony_ci| short | 2 | 2 | 2 | 2 | 2 | 30e41f4b71Sopenharmony_ci| int | 4 | 4 | 4 | 2 | 8 | 31e41f4b71Sopenharmony_ci| long | **4** | **8** | **4** | 4 | 8 | 32e41f4b71Sopenharmony_ci| long long | 8 | 8 | 8 | 8 | 8 | 33e41f4b71Sopenharmony_ci| float | 4 | 4 | 4 | 4 | 4 | 34e41f4b71Sopenharmony_ci| double | 8 | 8 | 8 | 8 | 8 | 35e41f4b71Sopenharmony_ci| size_t | **4** | **8** | **8** | 4 | 8 | 36e41f4b71Sopenharmony_ci| pointer | **4** | **8** | **8** | 4 | 8 | 37e41f4b71Sopenharmony_ci 38e41f4b71Sopenharmony_ci上表中只包含了部分基本类型,下表分别将ILP32和LP64的sizeof和print进行对比,展示了更全面的常量和类型对应的差异: 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ci| Type | ILP32 sizeof | ILP32 print | LP64 sizeof | LP64 print | 备注 | 41e41f4b71Sopenharmony_ci| ------------------ | ------------ | ----------- | ----------- | ---------- | ------ | 42e41f4b71Sopenharmony_ci| bool | 1 | %u | 1 | %u | C++ | 43e41f4b71Sopenharmony_ci| char | 1 | %d或%c | 1 | %d或%c | | 44e41f4b71Sopenharmony_ci| unsigned char | 1 | %u | 1 | %u | | 45e41f4b71Sopenharmony_ci| short | 2 | %d | 2 | %d | | 46e41f4b71Sopenharmony_ci| unsigned short | 2 | %u | 2 | %u | | 47e41f4b71Sopenharmony_ci| int | 4 | %d | 4 | %d | | 48e41f4b71Sopenharmony_ci| unsigned int | 4 | %u | 4 | %u | | 49e41f4b71Sopenharmony_ci| long | 4 | %ld | **8** | %ld | 有差异 | 50e41f4b71Sopenharmony_ci| unsigned long | 4 | %lu | **8** | %lu | 有差异 | 51e41f4b71Sopenharmony_ci| long int | 4 | %ld | **8** | %ld | 有差异 | 52e41f4b71Sopenharmony_ci| unsigned long int | 4 | %lu | **8** | %lu | 有差异 | 53e41f4b71Sopenharmony_ci| long long | 8 | %lld | 8 | %lld | | 54e41f4b71Sopenharmony_ci| unsigned long long | 8 | %llu | 8 | %llu | | 55e41f4b71Sopenharmony_ci| type \* | 4 | %p | **8** | %p | 有差异 | 56e41f4b71Sopenharmony_ci| pid_t | 4 | %d | 4 | %d | | 57e41f4b71Sopenharmony_ci| socklen_t | 4 | %u | 4 | %u | | 58e41f4b71Sopenharmony_ci| off_t | 4 | %zd | **8** | %zd | 有差异 | 59e41f4b71Sopenharmony_ci| time_t | 4 | %zd | 8 | %zd | 有差异 | 60e41f4b71Sopenharmony_ci| pthread_t | 4 | %zu | **8** | %zu | 有差异 | 61e41f4b71Sopenharmony_ci| size_t | 4 | %zu | 8 | %zu | 有差异 | 62e41f4b71Sopenharmony_ci| ssize_t | 4 | %zd | **8** | %zd | 有差异 | 63e41f4b71Sopenharmony_ci 64e41f4b71Sopenharmony_ci#### 数据结构对齐的差异 65e41f4b71Sopenharmony_ci 66e41f4b71Sopenharmony_ci##### 包含指针数据结构对齐的变化 67e41f4b71Sopenharmony_ci 68e41f4b71Sopenharmony_ci```c 69e41f4b71Sopenharmony_citypedef struct tagFoo { 70e41f4b71Sopenharmony_ci void *p; 71e41f4b71Sopenharmony_ci uint32_t i; 72e41f4b71Sopenharmony_ci} Foo; 73e41f4b71Sopenharmony_ci``` 74e41f4b71Sopenharmony_ci 75e41f4b71Sopenharmony_ci在32位系统上,指针长度为4,Foo 4字节对齐,sizeof(Foo) 等于8,在64位系统上,指针长度为8,Foo 8字节对齐,sizeof(Foo) 等于16。 76e41f4b71Sopenharmony_ci 77e41f4b71Sopenharmony_ci##### 包含64位整形的数据结构对齐的变化 78e41f4b71Sopenharmony_ci 79e41f4b71Sopenharmony_ci```c 80e41f4b71Sopenharmony_citypedef struct tagFoo { 81e41f4b71Sopenharmony_ci uint64_t p; 82e41f4b71Sopenharmony_ci uint32_t i; 83e41f4b71Sopenharmony_ci} Foo; 84e41f4b71Sopenharmony_ci``` 85e41f4b71Sopenharmony_ci 86e41f4b71Sopenharmony_ci虽然uint64_t是定长的,但由于对齐的存在,Foo的大小也是不同的。在32位系统上,Foo 4字节对齐,sizeof(Foo) 等于12,在64位系统上,Foo 8字节对齐,sizeof(Foo) 等于16。uint64_t替换为double,上述结论依然成立。 87e41f4b71Sopenharmony_ci 88e41f4b71Sopenharmony_ci### 约定 89e41f4b71Sopenharmony_ci 90e41f4b71Sopenharmony_ci**规则**:编程时必须遵守的约定(must) 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ci**建议**:编程时应该遵守的约定(should) 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_ci## 编程指导 95e41f4b71Sopenharmony_ci 96e41f4b71Sopenharmony_ci### 总则 97e41f4b71Sopenharmony_ci 98e41f4b71Sopenharmony_ci#### 【规则】开发者贡献的代码应当遵循此规范,编写出可同时应用于32位和64位的代码 99e41f4b71Sopenharmony_ci 100e41f4b71Sopenharmony_ci【说明】由于OpenHarmony会长期同时存在32位的运行环境和64位的运行环境,为了代码的一致性,开发者在编码时需要充分考虑代码的可移植能力。 101e41f4b71Sopenharmony_ci 102e41f4b71Sopenharmony_ci### 数据类型定义和格式化 103e41f4b71Sopenharmony_ci 104e41f4b71Sopenharmony_ci#### 【规则】应当使用统一定义的数据类型定义变量,无特殊意义或要求应当避免自行定义基本数据类型 105e41f4b71Sopenharmony_ci 106e41f4b71Sopenharmony_ci【说明】基于可移植性要求,在32位和64位条件下,可变长度的数据类型可能导致兼容性错误,为简单清晰,要求采用归一清晰的数据类型进行定义。基于当前的要求,定义下列基础数据类型: 107e41f4b71Sopenharmony_ci 108e41f4b71Sopenharmony_ci| 类型定义 | ILP32 | LP64 | PRINT | 使用场景及代替类型 | 109e41f4b71Sopenharmony_ci| ---------------- | ----- | ----- | ------- | ------------------------------------------------------------ | 110e41f4b71Sopenharmony_ci| void | - | - | - | void,无类型,仅用于占位和通用指针定义 | 111e41f4b71Sopenharmony_ci| char | 1 | 1 | %c | 对于字符串、数组直接使用原生char | 112e41f4b71Sopenharmony_ci| int8_t | 1 | 1 | %d | 对于1字节整型使用int8_t,uint8_t | 113e41f4b71Sopenharmony_ci| uint8_t | 1 | 1 | %u | 对于1字节整型使用int8_t,uint8_t | 114e41f4b71Sopenharmony_ci| int16_t | 2 | 2 | %d | 代替short | 115e41f4b71Sopenharmony_ci| uint16_t | 2 | 2 | %u | 代替unsigned short | 116e41f4b71Sopenharmony_ci| int32_t | 4 | 4 | %d | 代替int | 117e41f4b71Sopenharmony_ci| uint32_t | 4 | 4 | %u | 代替unsigned int | 118e41f4b71Sopenharmony_ci| int64_t | 8 | 8 | %PRId64 | 代替long long、宏实现代码兼容 | 119e41f4b71Sopenharmony_ci| uint64_t | 8 | 8 | %PRIu64 | 代替unsigned long long、宏实现代码兼容 | 120e41f4b71Sopenharmony_ci| float | 4 | 4 | %f | 单精度浮点数 | 121e41f4b71Sopenharmony_ci| double | 8 | 8 | %lf | 双精度浮点数 | 122e41f4b71Sopenharmony_ci| bool | 1 | 1 | %d | 布尔类型 | 123e41f4b71Sopenharmony_ci| uintptr_t | **4** | **8** | %zu | 会根据32位和64位的不同定义为不同的长度,用于可能存储指针的场景 | 124e41f4b71Sopenharmony_ci| type \* | **4** | **8** | %p | type \*,可变长度类型,与uintptr_t等价,存在类型转换时建议使用uintptr_t | 125e41f4b71Sopenharmony_ci| nullptr_t | **4** | **8** | %p | 指针初始化 | 126e41f4b71Sopenharmony_ci| pid_t | 4 | 4 | %d | Linux内置,固定长度 | 127e41f4b71Sopenharmony_ci| socklen_t | 4 | 4 | %u | Linux内置,固定长度 | 128e41f4b71Sopenharmony_ci| off_t/time_t | **4** | **8** | %zd | 可变长度类型,有符号 | 129e41f4b71Sopenharmony_ci| size_t/pthread_t | **4** | **8** | %zu | 可变长度类型,无符号,仅用于调用库函数的兼容性要求(比如底层API中使用了size_t) | 130e41f4b71Sopenharmony_ci 131e41f4b71Sopenharmony_ci上述类型定义在stddef.h(C)和cstdint(C++)标准库中,在采用#define重定义相关类型时,其源头应来自于上述类型。 132e41f4b71Sopenharmony_ci 133e41f4b71Sopenharmony_ci非特殊情况,不要使用非标准类型。禁止定义通用基础类型,除非定义的类型有明确的特定含义。对于涉及到第三方接口及API调用中使用的基础数据类型,以相关专项规则为准。 134e41f4b71Sopenharmony_ci 135e41f4b71Sopenharmony_ci【示例】非必要禁止自定义基础数据类型: 136e41f4b71Sopenharmony_ci 137e41f4b71Sopenharmony_ci```c 138e41f4b71Sopenharmony_ci// 禁止使用下面代码来重定义 139e41f4b71Sopenharmony_citypedef unsigned int UINT32;// 此定义禁止使用 140e41f4b71Sopenharmony_ci 141e41f4b71Sopenharmony_ci// 已经有内置的uint32_t完全可代替上述定义,因此上述定义没有存在的必要。但如果定义的类型有明确的专用意义,则可以保留定义: 142e41f4b71Sopenharmony_citypedef uint32_t DB_TABLE_ID; // 此定义可以保留 143e41f4b71Sopenharmony_ci``` 144e41f4b71Sopenharmony_ci 145e41f4b71Sopenharmony_ci【示例】下面2个类型的长度与通常理解不一致,禁止使用: 146e41f4b71Sopenharmony_ci 147e41f4b71Sopenharmony_ci| 类型定义 | ILP32 | LP64 | PRINT | 使用场景及代替类型 | 148e41f4b71Sopenharmony_ci| -------- | ------ | ----- | ----- | ---------------------- | 149e41f4b71Sopenharmony_ci| float_t | **12** | **4** | - | 长度不合常理,禁止使用 | 150e41f4b71Sopenharmony_ci| double_t | **12** | **8** | - | 长度不合常理,禁止使用 | 151e41f4b71Sopenharmony_ci 152e41f4b71Sopenharmony_ci#### 【建议】应当避免使用非统一定义的可变长类型定义变量,为适配平台、第三方代码接口等使用,需要特殊说明 153e41f4b71Sopenharmony_ci 154e41f4b71Sopenharmony_ci【说明】原生的long、int、short、size_t等类型,在64位和32位下其长度不确定,在编码时容易疏忽而导致代码隐患。如果将此类型用于外部存储或通信,则很容易导致系统间的不兼容,因此无特殊需求原则上应当避免使用这些类型。 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ci【例外】如果因为平台、第三方、库函数等原因,可以有限使用。使用这些类型定义时需要增加说明方便理解。 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ci【示例】 159e41f4b71Sopenharmony_ci 160e41f4b71Sopenharmony_ci```c 161e41f4b71Sopenharmony_cilong var; 162e41f4b71Sopenharmony_ci// 该定义在64位下为8bytes,在32位下为4bytes,存在歧义,建议修改为uint32_t或uint64_t。 163e41f4b71Sopenharmony_ci``` 164e41f4b71Sopenharmony_ci 165e41f4b71Sopenharmony_ci#### 【规则】避免使用uchar类型定义变量 166e41f4b71Sopenharmony_ci 167e41f4b71Sopenharmony_ci【说明】uchar或unsigned char用来定义字符串是一种不规范用法。对当前代码中已经存在的使用,需要修改为char类型(确认是字符串)或uint8_t(确认是无符号整数)。 168e41f4b71Sopenharmony_ci 169e41f4b71Sopenharmony_ci对于涉及到8bit编码的非ANSI字符序列,建议仍然使用char类型来定义。C++情况下,可使用wchar等宽字符类型定义。 170e41f4b71Sopenharmony_ci 171e41f4b71Sopenharmony_ci#### 【规则】当需要采用整型变量来存储指针时,变量应该定义成uintptr_t以适应不同的位宽 172e41f4b71Sopenharmony_ci 173e41f4b71Sopenharmony_ci【说明】uintptr_t类型用于用于存储指针长度的数据,其长度在32位和64位可自动适应。 174e41f4b71Sopenharmony_ci 175e41f4b71Sopenharmony_ci【示例】 176e41f4b71Sopenharmony_ci 177e41f4b71Sopenharmony_ci```c 178e41f4b71Sopenharmony_ciuintptr_t sessionPtr; 179e41f4b71Sopenharmony_ci 180e41f4b71Sopenharmony_ci// 将指针存储为变量时,强转和左值都应定义为uintptr_t,以适配不同场景字长的变化 181e41f4b71Sopenharmony_cisessionPtr = (uintptr_t) GetMemAddress(); 182e41f4b71Sopenharmony_ci``` 183e41f4b71Sopenharmony_ci 184e41f4b71Sopenharmony_ci#### 【建议】函数入参或返回值定义的类型与变量类型发生不匹配时候,需要谨慎处理,以保证按照赋值和类型转换的规则进行转换后的结果正确 185e41f4b71Sopenharmony_ci 186e41f4b71Sopenharmony_ci【说明】如果不可避免出现了类型不一致的情况,需要谨慎进行类型转换,确保转换后的结果满足实际应用需求。 187e41f4b71Sopenharmony_ci 188e41f4b71Sopenharmony_ci【示例】 189e41f4b71Sopenharmony_ci 190e41f4b71Sopenharmony_ci```c 191e41f4b71Sopenharmony_cilong function (long l); 192e41f4b71Sopenharmony_ciint main () { 193e41f4b71Sopenharmony_ci int i = -2; 194e41f4b71Sopenharmony_ci unsigned int k = 1U; 195e41f4b71Sopenharmony_ci long n = function(i + k); 196e41f4b71Sopenharmony_ci} 197e41f4b71Sopenharmony_ci``` 198e41f4b71Sopenharmony_ci 199e41f4b71Sopenharmony_ci【注释】上面这段代码在 64 位系统上会失败,因为表达式 (i + k) 是一个无符号的 32 位表达式,在将其转换成 long 类型时,符号并没有得到扩展。入参的结果是不正确的。解决方案是将其中一个操作数强制转换成 64 位的类型。 200e41f4b71Sopenharmony_ci 201e41f4b71Sopenharmony_ci#### 【规则】打印64位的整数请使用%PRId64,%PRIu64,%PRIx64等64位兼容宏进行格式化输出,不允许使用%d,%ld,%zd,%x,%lx等不兼容输出 202e41f4b71Sopenharmony_ci 203e41f4b71Sopenharmony_ci【说明】如果待格式化的数据明确为64位类型(定义为uint64_t),其输出格式化应当采用下述方法: 204e41f4b71Sopenharmony_ci 205e41f4b71Sopenharmony_ci```c 206e41f4b71Sopenharmony_ci#include <stdio.h> 207e41f4b71Sopenharmony_ci#include <stdint.h> 208e41f4b71Sopenharmony_ci#include <inttypes.h> 209e41f4b71Sopenharmony_ci 210e41f4b71Sopenharmony_ciint main() 211e41f4b71Sopenharmony_ci{ 212e41f4b71Sopenharmony_ci uint64_t a = 0x1234567fffffff; 213e41f4b71Sopenharmony_ci printf("a = %"PRIx64"\n", a); 214e41f4b71Sopenharmony_ci return 0; 215e41f4b71Sopenharmony_ci} 216e41f4b71Sopenharmony_ci``` 217e41f4b71Sopenharmony_ci 218e41f4b71Sopenharmony_ci上述输出代码,在32位和64位环境下均能够正常输出64位长度数字。如果采用其它格式处理,都存在兼容性问题,需要注意避免,如下表: 219e41f4b71Sopenharmony_ci 220e41f4b71Sopenharmony_ci| 格式化方法 | ILP32构建 | ILP32结果 | LP64构建 | LP64结果 | 结论 | 221e41f4b71Sopenharmony_ci| ---------- | -------------- | --------- | -------------- | -------- | ---------- | 222e41f4b71Sopenharmony_ci| %lx | 类型不匹配告警 | 错误 | 无告警 | 正确 | **不兼容** | 223e41f4b71Sopenharmony_ci| %zx | 类型不匹配告警 | 错误 | 无告警 | 正确 | **不兼容** | 224e41f4b71Sopenharmony_ci| %llx | 无告警 | 正确 | 类型不匹配告警 | 正确 | **不兼容** | 225e41f4b71Sopenharmony_ci| %p | 类型不匹配告警 | 错误 | 类型不匹配告警 | 正确 | **不兼容** | 226e41f4b71Sopenharmony_ci| %PRIx64 | 无告警 | 正确 | 无告警 | 正确 | 兼容 | 227e41f4b71Sopenharmony_ci 228e41f4b71Sopenharmony_ci【示例】类型不匹配告警信息示例: 229e41f4b71Sopenharmony_ci 230e41f4b71Sopenharmony_ci```bash 231e41f4b71Sopenharmony_ci# 32位编译 232e41f4b71Sopenharmony_ciformat ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘uint64_t {aka long long unsigned int}’ 233e41f4b71Sopenharmony_ciformat ‘%zx’ expects argument of type ‘size_t’, but argument 2 has type ‘uint64_t {aka long long unsigned int}’ 234e41f4b71Sopenharmony_ciformat ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘uint64_t {aka long long unsigned int}’ 235e41f4b71Sopenharmony_ci 236e41f4b71Sopenharmony_ci# 64位编译 237e41f4b71Sopenharmony_ciformat ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘uint64_t {aka long unsigned int}’ 238e41f4b71Sopenharmony_ciformat ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘uint64_t {aka long unsigned int}’ 239e41f4b71Sopenharmony_ci``` 240e41f4b71Sopenharmony_ci 241e41f4b71Sopenharmony_ci#### 【规则】打印输出可变类型数据,对齐时要考虑数据长度并预留足够空间 242e41f4b71Sopenharmony_ci 243e41f4b71Sopenharmony_ci【说明】32位下指针及size_t长度最大只有8位(16进制)或10位(10进制),但在64位系统下,其最大宽度可达到20位,因此在打印输出时需要充分考虑其范围,避免打印因不对齐而影响用户体验。 244e41f4b71Sopenharmony_ci 245e41f4b71Sopenharmony_ci#### 【规则】使用常量时,禁止采用L/UL作后缀,允许增加U后缀指定为unsigned int类型,允许增加LL/ULL后缀指定其长度为64位 246e41f4b71Sopenharmony_ci 247e41f4b71Sopenharmony_ci【说明】无后缀的常量缺省为int类型;采用L/UL为后缀时,在32位和64位系统下,长度可能发生变化;确定需要64位时,采用LL/ULL为后缀定义以确保在32位和64位系统下均为64位长度。 248e41f4b71Sopenharmony_ci 249e41f4b71Sopenharmony_ci| 常量定义 | ILP32 | LP64 | 使用场景 | 250e41f4b71Sopenharmony_ci| -------------- | --------- | ----- | ------------------------------------------------------------ | 251e41f4b71Sopenharmony_ci| 1 | 4 | 4 | 默认为int32_t类型,长度固定 | 252e41f4b71Sopenharmony_ci| 1U | 4 | 4 | 默认为uint32_t类型,长度固定 | 253e41f4b71Sopenharmony_ci| 1L | **4** | **8** | 后缀为L或UL,长度不同,应当避免使用 | 254e41f4b71Sopenharmony_ci| 1UL | **4** | **8** | 后缀为L或UL,长度不同,应当避免使用 | 255e41f4b71Sopenharmony_ci| 1LL | 8 | 8 | 默认为int64_t类型,长整形数据,直接使用LL,确定为64位,长度固定 | 256e41f4b71Sopenharmony_ci| 1ULL | 8 | 8 | uint64_t类型,无符号长整形数据 | 257e41f4b71Sopenharmony_ci| 0x7FFFFFFF | 4 | 4 | 不携带附加符号的数字,不超过int32_t的范围,默认为int32_t类型 | 258e41f4b71Sopenharmony_ci| 0x7FFFFFFFL | **4** | **8** | 长度不同,避免使用 | 259e41f4b71Sopenharmony_ci| 0x7FFFFFFFLL | 8 | 8 | 长度固定 | 260e41f4b71Sopenharmony_ci| 0x80000000 | 4 | 4 | 小于uint32_t范围,类型为uint32_t类型 | 261e41f4b71Sopenharmony_ci| 0x80000000L | **4** | **8** | 后缀为L,小于uint32_t范围,增加该参数没有意义,应当避免使用 | 262e41f4b71Sopenharmony_ci| 0x80000000LL | 8 | 8 | 增加LL后缀,小于uint32_t范围,长度固定 | 263e41f4b71Sopenharmony_ci| 0x8000000000 | **NA或8** | **8** | 无后缀,超过uint32_t的范围,编译器默认为LL或无效,64位下固定为uint64_t类型 | 264e41f4b71Sopenharmony_ci| 0x8000000000L | **NA或8** | **8** | 后缀为L,对超过uint32_t的范围常数,增加该参数没有意义,应当避免使用 | 265e41f4b71Sopenharmony_ci| 0x8000000000LL | 8 | 8 | 后缀为LL,uint64_t类型 | 266e41f4b71Sopenharmony_ci 267e41f4b71Sopenharmony_ci从上表中可看出,使用L或UL后缀的常量,其长度在32位和64位下发生变化,不利于代码的可移植性,因此禁止使用这个后缀。 268e41f4b71Sopenharmony_ci 269e41f4b71Sopenharmony_ci【示例】 270e41f4b71Sopenharmony_ci 271e41f4b71Sopenharmony_ci```c 272e41f4b71Sopenharmony_ci// 下面定义中的UL是没有意义的,在32位系统会出错,在64位系统不需要 273e41f4b71Sopenharmony_ci#define YYY_START_ADDRESS(XXX_START_ADDR + 0x80000000UL) 274e41f4b71Sopenharmony_ci``` 275e41f4b71Sopenharmony_ci 276e41f4b71Sopenharmony_ci#### 【规则】应当使用标准头文件中定义的宏常量,避免自行定义 277e41f4b71Sopenharmony_ci 278e41f4b71Sopenharmony_ci【说明】C(stdint.h)和C++(cstdint.h)的标准头文件中均有定义最大值/最小值的宏常量,源文件中引用即可,避免自行定义。 279e41f4b71Sopenharmony_ci 280e41f4b71Sopenharmony_ci【示例】 281e41f4b71Sopenharmony_ci 282e41f4b71Sopenharmony_ci```c 283e41f4b71Sopenharmony_ci#include <cstdio> 284e41f4b71Sopenharmony_ci#include <cinttypes> 285e41f4b71Sopenharmony_ci 286e41f4b71Sopenharmony_ciint main() 287e41f4b71Sopenharmony_ci{ 288e41f4b71Sopenharmony_ci std::printf("%zu\n", sizeof(std::int64_t)); 289e41f4b71Sopenharmony_ci std::printf("%s\n", PRId64); 290e41f4b71Sopenharmony_ci std::printf("%+" PRId64 "\n", INT64_MIN); 291e41f4b71Sopenharmony_ci std::printf("%+" PRId64 "\n", INT64_MAX); 292e41f4b71Sopenharmony_ci 293e41f4b71Sopenharmony_ci std::int64_t n = 7; 294e41f4b71Sopenharmony_ci std::printf("%+" PRId64 "\n", n); 295e41f4b71Sopenharmony_ci} 296e41f4b71Sopenharmony_ci``` 297e41f4b71Sopenharmony_ci 298e41f4b71Sopenharmony_ci#### 【规则】应当使用统一的定义表示常量的无效值,避免直接使用全F等表示方法以适应不同的长度 299e41f4b71Sopenharmony_ci 300e41f4b71Sopenharmony_ci【说明】同一个数字常量值在64位系统和32位系统上,按照32位系统有无符号类型,理解的结果可能不一样;特别是32位系统上最高bit位为1的,在32位系统上按照有符号类型理解成一个负数,在64位系统上是一个正数。要求统一使用typedef.h中的统一定义,表示数据的无效值。 301e41f4b71Sopenharmony_ci 302e41f4b71Sopenharmony_ci```c 303e41f4b71Sopenharmony_ci// 使用typedef.h中的定义 304e41f4b71Sopenharmony_ci#define INVALID_INT8((int8_t)(-1)) 305e41f4b71Sopenharmony_ci#define INVALID_UINT8((uint8_t)(-1)) 306e41f4b71Sopenharmony_ci#define INVALID_INT16((int16_t)(-1)) 307e41f4b71Sopenharmony_ci#define INVALID_UINT16((uint16_t)(-1)) 308e41f4b71Sopenharmony_ci#define INVALID_INT32((int32_t)(-1)) 309e41f4b71Sopenharmony_ci#define INVALID_UINT32((uint32_t)(-1)) 310e41f4b71Sopenharmony_ci#define INVALID_INT64((int64_t)(-1)) 311e41f4b71Sopenharmony_ci#define INVALID_UINT64((uint64_t)(-1)) 312e41f4b71Sopenharmony_ci``` 313e41f4b71Sopenharmony_ci 314e41f4b71Sopenharmony_ci【示例】 315e41f4b71Sopenharmony_ci 316e41f4b71Sopenharmony_ci```c 317e41f4b71Sopenharmony_ci// 在32位系统上,n是一个负数 318e41f4b71Sopenharmony_cilong n = 0xFFFFFFFF; 319e41f4b71Sopenharmony_ci// 在64位系统上,n是一个正数,实际值为0x00000000FFFFFFFF。 320e41f4b71Sopenharmony_cilong n = 0xFFFFFFFF; 321e41f4b71Sopenharmony_ci``` 322e41f4b71Sopenharmony_ci 323e41f4b71Sopenharmony_ci#### 【建议】对不会超过32位空间大小的临时变量,建议采用uint32_t定义 324e41f4b71Sopenharmony_ci 325e41f4b71Sopenharmony_ci【说明】定义的变量不需要特别关注其类型,可采用默认的uint32_t类型,以减少因类型不一致导致的大量强制类型转换。 326e41f4b71Sopenharmony_ci 327e41f4b71Sopenharmony_ci### 结构体对齐与填充 328e41f4b71Sopenharmony_ci 329e41f4b71Sopenharmony_ci#### 【规则】代码中禁止采用常量硬编码来指定变量长度、结构体长度,应当使用sizeof等内建类型来获取 330e41f4b71Sopenharmony_ci 331e41f4b71Sopenharmony_ci【说明】sizeof可自动计算相关变量和结构的长度,避免硬编码错误;同时在编译时即完成了所属变量长度的计算,不会影响运行性能。 332e41f4b71Sopenharmony_ci 333e41f4b71Sopenharmony_ci在64位系统下默认对齐方式是8字节对齐,使用sizeof()获取结构体长度来取代硬编码,以避免因结构对齐导致的长度计算错误。 334e41f4b71Sopenharmony_ci 335e41f4b71Sopenharmony_ci联合在使用时,需要特别关注到其长度在64位和32位下的不同,避免在计算长度时出现错误。特别是按照最大长度进行计算和空间申请。 336e41f4b71Sopenharmony_ci 337e41f4b71Sopenharmony_ci【示例】未采用sizeof计算结构长度,可能导致内存空间不足。 338e41f4b71Sopenharmony_ci 339e41f4b71Sopenharmony_ci```c 340e41f4b71Sopenharmony_ciint32_t *p; 341e41f4b71Sopenharmony_cip = (int32_t *)malloc(4 * ELEMENTS_NUMBER); 342e41f4b71Sopenharmony_ci// 这行代码假定指针的长度为4字节,而这在LP64中是不正确的,此时是8字节。 343e41f4b71Sopenharmony_ci 344e41f4b71Sopenharmony_ci//正确的方法应使用sizeof() 345e41f4b71Sopenharmony_ciint32_t *p; 346e41f4b71Sopenharmony_cip = (int32_t *)malloc(sizeof(p) * ELEMENTS_NUMBER); 347e41f4b71Sopenharmony_ci``` 348e41f4b71Sopenharmony_ci 349e41f4b71Sopenharmony_ci#### 【建议】特殊情况下,64位系统可以强制编译器指定对齐方式 350e41f4b71Sopenharmony_ci 351e41f4b71Sopenharmony_ci【说明】在需要时,为保持代码兼容性,可采用指定对齐方式。使用伪指令#pragma pack (n),编译器将按照n 个字节对齐;使用伪指令#pragma pack (),取消自定义字节对齐方式。 352e41f4b71Sopenharmony_ci 353e41f4b71Sopenharmony_ci【样例】 354e41f4b71Sopenharmony_ci 355e41f4b71Sopenharmony_ci```c 356e41f4b71Sopenharmony_ci#pragma pack(push) // 保存当前的对齐方式 357e41f4b71Sopenharmony_ci#pragma pack(1) // 设置对齐方式为1字节对齐 358e41f4b71Sopenharmony_cistruct test 359e41f4b71Sopenharmony_ci{ 360e41f4b71Sopenharmony_ci ...... 361e41f4b71Sopenharmony_ci}; 362e41f4b71Sopenharmony_ci#pragma pack(pop) // 恢复之前的对齐方式 363e41f4b71Sopenharmony_ci``` 364e41f4b71Sopenharmony_ci 365e41f4b71Sopenharmony_ci#### 【规则】涉及多机通信的消息结构体,需要对齐统一。基于兼容性考虑,可优先采用1字节对齐;禁止使用8字节对齐和64位数据类型以避免与32位系统通信错误 366e41f4b71Sopenharmony_ci 367e41f4b71Sopenharmony_ci【说明】板间通信消息涉及到跨板操作,除非所有软件同步升级,否则将会导致通信失败。为兼容性考虑,对已经存在的协议和结构,保持1字节对齐,并转换为网络序。对新增的通信协议,为通信效率和处理性能考虑,可以有条件采用4字节对齐。 368e41f4b71Sopenharmony_ci 369e41f4b71Sopenharmony_ci#### 【规则】对外提供的接口数据结构应当避免出现填充,至少要求采用4字节对齐 370e41f4b71Sopenharmony_ci 371e41f4b71Sopenharmony_ci【说明】对功能特性对外提供的API头文件,如果其中涉及到结构体定义,应当避免结构体填充,建议能够在自然对齐情况下数据不出现空洞,至少需要保证4字节对齐。 372e41f4b71Sopenharmony_ci 373e41f4b71Sopenharmony_ci#### 【建议】应当使用成员名称访问结构体成员,禁止使用偏移方式访问 374e41f4b71Sopenharmony_ci 375e41f4b71Sopenharmony_ci【说明】数据结构成员的偏移在32位和64位对齐情况下,其偏移值不同,不能直接计算每个成员的大小之后作为偏移;在32位系统上没有自动填充的数据结构,到了64位上有可能出现自动填充。 376e41f4b71Sopenharmony_ci 377e41f4b71Sopenharmony_ci【示例】 378e41f4b71Sopenharmony_ci 379e41f4b71Sopenharmony_ci```c 380e41f4b71Sopenharmony_ciStruct A 381e41f4b71Sopenharmony_ci{ 382e41f4b71Sopenharmony_ci uint32_t a; 383e41f4b71Sopenharmony_ci uint32_t *p; 384e41f4b71Sopenharmony_ci uint32_t b; 385e41f4b71Sopenharmony_ci}; 386e41f4b71Sopenharmony_ci``` 387e41f4b71Sopenharmony_ci 388e41f4b71Sopenharmony_ci成员b的偏移等于sizeof(a) + sizeof(p)在32位系统上成立,在64位系统上不成立。正确的做法应当是直接通过变量名称进行索引定位: 389e41f4b71Sopenharmony_ci 390e41f4b71Sopenharmony_ci```c 391e41f4b71Sopenharmony_cixxx.b = 123; 392e41f4b71Sopenharmony_ci``` 393e41f4b71Sopenharmony_ci 394e41f4b71Sopenharmony_ci如果结构定义比较特殊,比如结构体只是消息的头部,后续还有其它字段,则可能需要重新定义此结构,使结构体内部不出现填充字段。 395e41f4b71Sopenharmony_ci 396e41f4b71Sopenharmony_ci【示例】 397e41f4b71Sopenharmony_ci 398e41f4b71Sopenharmony_ci```c 399e41f4b71Sopenharmony_citypedef struct { 400e41f4b71Sopenharmony_ci uint32_t self; /* 其它对齐结构 */ 401e41f4b71Sopenharmony_ci uint32_t brother; /* 其它对齐结构 */ 402e41f4b71Sopenharmony_ci uint8_t processedFlag; /* 当前节点是否被处理过的标志 */ 403e41f4b71Sopenharmony_ci uint8_t reserve[3]; /* 为了4字节对齐的保留字段 */ 404e41f4b71Sopenharmony_ci} TreeNodeInfo; 405e41f4b71Sopenharmony_ci 406e41f4b71Sopenharmony_citypedef struct { 407e41f4b71Sopenharmony_ci TreeNodeInfo nodeInfo; /* 每一个node的树信息的数据结构 */ 408e41f4b71Sopenharmony_ci void *userInfo; /* 每一个node的用户信息数据结构 */ 409e41f4b71Sopenharmony_ci} TreeNode; 410e41f4b71Sopenharmony_ci``` 411e41f4b71Sopenharmony_ci 412e41f4b71Sopenharmony_ciTreeNode结构体中有两个成员结构体,下面的代码中根据第二个成员来获取第一个成员的地址,采用第二个成员首地址减去sizeof(第一个成员)计算(inUserInfo指向结构体中的userInfo字段): 413e41f4b71Sopenharmony_ci 414e41f4b71Sopenharmony_ci```c 415e41f4b71Sopenharmony_ciinTreeNodeInfo = (TreeNodeInfo *)((void *)(((char *)inUserInfo) - sizeof(TreeNodeInfo))); 416e41f4b71Sopenharmony_ci``` 417e41f4b71Sopenharmony_ci 418e41f4b71Sopenharmony_ci结构体采用自然对齐,需要注意到子结构体TreeNodeInfo,在32位下其长度为12bytes,在64位下,**其长度也是12位**。结构体TreeNode在32位下成员结构体之间无填充,其长度为16bytes,但在64位下的结构体长度:sizeof(TreeNodeInfo)=12,sizeof(TreeNode)=24,即子结构体TreeNodeInfo后有4个字节的填充字段,因此在64位下通过上述方法获取前一个字段地址,就会漏算填充的4个字节,导致成员访问出错。 419e41f4b71Sopenharmony_ci 420e41f4b71Sopenharmony_ci#### 【建议】结构体定义时,为节省存储空间,在保证可读性的前提下,尽可能实现8字节自然对齐,避免出现填充 421e41f4b71Sopenharmony_ci 422e41f4b71Sopenharmony_ci【说明】如果结构体能够实现自然对齐,则不需要进行填充,可有效节省结构体的无效空间。在不影响可读性的前提下,建议将size_t和pointer等64位长度类型放在结构体两端定义。 423e41f4b71Sopenharmony_ci 424e41f4b71Sopenharmony_ci【示例】 425e41f4b71Sopenharmony_ci 426e41f4b71Sopenharmony_ci```c 427e41f4b71Sopenharmony_ci// 下面的结构体,在自然对齐情况下,其长度为24bytes 428e41f4b71Sopenharmony_cistruct Foo 429e41f4b71Sopenharmony_ci{ 430e41f4b71Sopenharmony_ci int32_t a; 431e41f4b71Sopenharmony_ci uint64_t l; 432e41f4b71Sopenharmony_ci int32_t x; 433e41f4b71Sopenharmony_ci} 434e41f4b71Sopenharmony_ci 435e41f4b71Sopenharmony_ci// 经过适当调整,可优化到16bytes 436e41f4b71Sopenharmony_cistruct Foo 437e41f4b71Sopenharmony_ci{ 438e41f4b71Sopenharmony_ci uint64_t l; 439e41f4b71Sopenharmony_ci int32_t a; 440e41f4b71Sopenharmony_ci int32_t x; 441e41f4b71Sopenharmony_ci} 442e41f4b71Sopenharmony_ci``` 443e41f4b71Sopenharmony_ci 444e41f4b71Sopenharmony_ci### 数据类型转换及运算 445e41f4b71Sopenharmony_ci 446e41f4b71Sopenharmony_ci#### 【规则】应当避免不同类型的数据之间的隐式类型转换,如果必要,应当采用显式类型转换,避免在32位和64位系统结果不一致 447e41f4b71Sopenharmony_ci 448e41f4b71Sopenharmony_ci【说明】谨慎处理不同长度和精度的操作数之间进行运算,避免因默认转换出现精度和符号的丢失。64位与32位混合编程情况下,需要关注隐式类型转换的几个重要点: 449e41f4b71Sopenharmony_ci 450e41f4b71Sopenharmony_ci1. 64位长度的变量给32长度变量赋值,低32位直接赋值,高32位被截断丢失;低32位再根据左值变量类型理解成有符号或者无符号 451e41f4b71Sopenharmony_ci 452e41f4b71Sopenharmony_ci2. 反之,32位长度的变量给64长度变量赋值,根据源32位为有符号或者无符号进行符号扩展,目的64位数再根据变量类型理解成有符号或者无符号。 453e41f4b71Sopenharmony_ci 454e41f4b71Sopenharmony_ci3. 有符号数与无符号数进行运算,如果不指定结果类型,系统默认按照无符号方式理解。 455e41f4b71Sopenharmony_ci 456e41f4b71Sopenharmony_ci上述转换过程可能带来不符合原意的结果,因此需要谨慎对待,尽可能避免隐式的转换。 457e41f4b71Sopenharmony_ci 458e41f4b71Sopenharmony_ci【示例】转换后结果看上去正确的示例 459e41f4b71Sopenharmony_ci 460e41f4b71Sopenharmony_ci```c 461e41f4b71Sopenharmony_ciint32_t t1 = -2; 462e41f4b71Sopenharmony_ciint64_t t2 = 1; 463e41f4b71Sopenharmony_ciint32_t t3 = t1 + t2; 464e41f4b71Sopenharmony_ciprintf("t3 = %d\n", t3); 465e41f4b71Sopenharmony_ci 466e41f4b71Sopenharmony_ci// 打印结果: t3 = -1 467e41f4b71Sopenharmony_ci``` 468e41f4b71Sopenharmony_ci 469e41f4b71Sopenharmony_cit1是个32位数,t2是个64位数,在做运算之前,先把t1也扩展成64位的。加法完成之后结果是一个64位的int64_t类型,在内存中16进制存储值为:0xffffffffffffffff,在给32位int32_t类型赋值发生截断, 值为0xffffffff,再理解成有符号32位,值为-1。此结果虽然看上去正确,但发生了数据截断,可能并不符合作者的本意。 470e41f4b71Sopenharmony_ci 471e41f4b71Sopenharmony_ci【示例】有符号向无符号转换 472e41f4b71Sopenharmony_ci 473e41f4b71Sopenharmony_ci```c 474e41f4b71Sopenharmony_ciint64_t t1 = -1; 475e41f4b71Sopenharmony_ciuint32_t t2 = t1; 476e41f4b71Sopenharmony_ciprintf("t2=%u", t2); 477e41f4b71Sopenharmony_ci 478e41f4b71Sopenharmony_ci// 打印结果:t2=4294967295 479e41f4b71Sopenharmony_ci``` 480e41f4b71Sopenharmony_ci 481e41f4b71Sopenharmony_cit1是个64位int64_t类型,用二进制表示为0xffffffffffffffff,如果赋值给一个32位int类型,高32位丢失,直接显示位低32位的值,二进制为0xffffffff,按照无符号方式理解,值为4294967295。 482e41f4b71Sopenharmony_ci 483e41f4b71Sopenharmony_ci【示例】32位向64位无符号转换 484e41f4b71Sopenharmony_ci 485e41f4b71Sopenharmony_ci```c 486e41f4b71Sopenharmony_ciint32_t t1 = -1; 487e41f4b71Sopenharmony_ciuint64_t t2 = t1; 488e41f4b71Sopenharmony_ciprintf("t2 = %lu\n", t2); 489e41f4b71Sopenharmony_ci 490e41f4b71Sopenharmony_ci// 打印结果:t2 = 18446744073709551615 491e41f4b71Sopenharmony_ci``` 492e41f4b71Sopenharmony_ci 493e41f4b71Sopenharmony_ci源32位是个有符号的负数,扩展时,应该带符号扩展,负数高位全部为f,扩展后值为0xffffffffffffffff。目的64位类型是个无符号的数,所以其值是一个很大的正数。 494e41f4b71Sopenharmony_ci 495e41f4b71Sopenharmony_ci#### 【规则】当需要将指针作为基址,再按照字节计算偏移时,指针需要强制转换为uintptr_t或uint8_t *等单字节指针类型 496e41f4b71Sopenharmony_ci 497e41f4b71Sopenharmony_ci【说明】如果转换为整型,采用uint32_t强转,会出现指针被截断的情况,因此需要转换为uintptr_t。也可转换为单字节宽度的指针类型,如uint8_t \*、char \*等,转为上述方式后,偏移均被理解为字节。void \*类型实际也会按照1字节进行偏移,但为了类型明确化,建议使用前面更明确的类型代替。 498e41f4b71Sopenharmony_ci 499e41f4b71Sopenharmony_ci【示例】 500e41f4b71Sopenharmony_ci 501e41f4b71Sopenharmony_ci```c 502e41f4b71Sopenharmony_ci// 错误 503e41f4b71Sopenharmony_civoid *pPkt = (void *)((uint32_t)MSG_GET_DATA_ADDR(msgAddr) + OFFSET); 504e41f4b71Sopenharmony_ci 505e41f4b71Sopenharmony_ci// 正确 506e41f4b71Sopenharmony_civoid *pPkt = (void *)((uintptr_t)MSG_GET_DATA_ADDR(msgAddr) + OFFSET); // C 507e41f4b71Sopenharmony_civoid *pPkt = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(MSG_GET_DATA_ADDR(msgAddr)) + OFFSET); // C++ 508e41f4b71Sopenharmony_ci``` 509e41f4b71Sopenharmony_ci 510e41f4b71Sopenharmony_ci#### 【规则】禁止指针与uint32_t之间相互赋值,包括函数参数传递 511e41f4b71Sopenharmony_ci 512e41f4b71Sopenharmony_ci【说明】如果要定义的变量可能是不确定长度的指针,使用void \*;如果要定义的变量既可以是指针,也可以是整形,使用uintptr_t。 513e41f4b71Sopenharmony_ci 514e41f4b71Sopenharmony_ci【示例】指针与整型的转换 515e41f4b71Sopenharmony_ci 516e41f4b71Sopenharmony_ci```c 517e41f4b71Sopenharmony_ciint32_t i, *p, *q; 518e41f4b71Sopenharmony_cip = &i; 519e41f4b71Sopenharmony_ciq = (int32_t *) (int32_t)&i; 520e41f4b71Sopenharmony_ci 521e41f4b71Sopenharmony_ci// 在A32架构下,p = q;但是在A64-LP64架构下,p != q 522e41f4b71Sopenharmony_ci``` 523e41f4b71Sopenharmony_ci 524e41f4b71Sopenharmony_ci为了避免这种类型冲突问题,可以用uintptr_t来表示指针类型。 525e41f4b71Sopenharmony_ci 526e41f4b71Sopenharmony_ci#### 【规则】禁止size_t与int32_t/uint32_t之间相互赋值,包括函数参数传递 527e41f4b71Sopenharmony_ci 528e41f4b71Sopenharmony_ci【说明】可变长度类型禁止与32长度类型强转。 529e41f4b71Sopenharmony_ci 530e41f4b71Sopenharmony_ci【示例】 531e41f4b71Sopenharmony_ci 532e41f4b71Sopenharmony_ci```c 533e41f4b71Sopenharmony_ciint32_t length = (int32_t)strlen(str); // 错误 534e41f4b71Sopenharmony_ci``` 535e41f4b71Sopenharmony_ci 536e41f4b71Sopenharmony_cistrlen返回size_t(它在LP64中是unsigned long),当赋值给一个int32_t时,截断是必然发生的。而通常,截断只会在str的长度大于2GB时才会发生,这种情况在程序中一般不会出现,容易忽略。 537e41f4b71Sopenharmony_ci 538e41f4b71Sopenharmony_ci#### 【规则】在64位环境下使用大数组或大for循环索引时,索引类型应当与下标边界保持一致 539e41f4b71Sopenharmony_ci 540e41f4b71Sopenharmony_ci【说明】如果系统中使用了超大数组或超大循环,在64位环境有可能超过32位的索引范围,则需要使用可变长度类型或64位类型来定义数组下标或循环变量,避免因变量范围不足而导致不能全量遍历。 541e41f4b71Sopenharmony_ci 542e41f4b71Sopenharmony_ci【示例】 543e41f4b71Sopenharmony_ci 544e41f4b71Sopenharmony_ci```c 545e41f4b71Sopenharmony_ciint64_t count = BIG_NUMBER; 546e41f4b71Sopenharmony_cifor (unsigned int index = 0; index != count; index++) 547e41f4b71Sopenharmony_ci ... 548e41f4b71Sopenharmony_ci``` 549e41f4b71Sopenharmony_ci 550e41f4b71Sopenharmony_ci在64位系统上,由于int64_t是64位类型,count是一个很大的数。unsigned int是32位类型 导致上面的循环永远不会终止。因此,index应该改成int64_t类型。 551e41f4b71Sopenharmony_ci 552e41f4b71Sopenharmony_ci### 位域和字节序 553e41f4b71Sopenharmony_ci 554e41f4b71Sopenharmony_ci#### 【规则】基于位域的变量定义需要充分考虑位域的基础类型及对齐问题,避免在不同的位宽下计算出错 555e41f4b71Sopenharmony_ci 556e41f4b71Sopenharmony_ci【说明】位域的宽度需要结合对齐进行理解,结构体会变长;对位域的取值需要采用名称,避免采用直接计算。 557e41f4b71Sopenharmony_ci 558e41f4b71Sopenharmony_ci#### 【规则】在64位系统上,考虑移位操作带来的长度差异,以及移位以后生成的值隐形扩展到64位的问题 559e41f4b71Sopenharmony_ci 560e41f4b71Sopenharmony_ci【说明】位移运算时,需要检查是否可能导致溢出而回绕的情况,需要修改为32位类型避免结果不一致。 561e41f4b71Sopenharmony_ci 562e41f4b71Sopenharmony_ci【示例】 563e41f4b71Sopenharmony_ci 564e41f4b71Sopenharmony_ci```c 565e41f4b71Sopenharmony_ciint64_t t = 1 << a; // 需考虑a的大小 566e41f4b71Sopenharmony_ci``` 567e41f4b71Sopenharmony_ci 568e41f4b71Sopenharmony_ci在32位系统上,a的最大值是32,在64位系统上,是64。如果a是一个32位变量,其结果还要考虑到64位扩展问题。 569e41f4b71Sopenharmony_ci 570e41f4b71Sopenharmony_ci### 第三方库和差异化功能 571e41f4b71Sopenharmony_ci 572e41f4b71Sopenharmony_ci#### 【规则】64位系统使用到的第三方类库,都必须是支持64位的 573e41f4b71Sopenharmony_ci 574e41f4b71Sopenharmony_ci【说明】部分库函数、第三方开源代码本身对64位的支持不定完善,需要针对所有涉及的代码进行评估,确保其可运行在64位环境下。部分库函数在64位和32位采用不同的接口实现,因此需要确保使用正确的接口。 575e41f4b71Sopenharmony_ci 576e41f4b71Sopenharmony_ci【示例】内存映射处理,在32位系统下可使用mmap,如果映射超过2GBytes,则需要使用mmap64;但64位系统下可统一使用mmap。 577e41f4b71Sopenharmony_ci 578e41f4b71Sopenharmony_ci#### 【规则】涉及到底层汇编的功能,需要在64位和32位系统分别独立调测,避免功能不可用 579e41f4b71Sopenharmony_ci 580e41f4b71Sopenharmony_ci【说明】切换到64位后,寄存器个数和位宽都有变化,涉及到汇编的相关调测功能都需要进行重新的调测,并需要同时关注32位和64位下的代码有效性。 581e41f4b71Sopenharmony_ci 582e41f4b71Sopenharmony_ci【示例】调用栈的推栈功能,在32位和64位内嵌的汇编代码需要独立编写调测。 583e41f4b71Sopenharmony_ci 584e41f4b71Sopenharmony_ci#### 【规则】补丁功能需要同时支持32位指令和64位指令差异 585e41f4b71Sopenharmony_ci 586e41f4b71Sopenharmony_ci【说明】由于指令长度变更,补丁机制及功能需要适配修改。 587e41f4b71Sopenharmony_ci 588e41f4b71Sopenharmony_ci#### 【规则】64位系统使用到的工具,都必须是支持64位的 589e41f4b71Sopenharmony_ci 590e41f4b71Sopenharmony_ci【说明】如果不可避免出现了类型不一致的情况,需要谨慎进行类型转换,确保转换后的结果满足实际应用需求。 591