C编译器是否提供确定长度的类型定义?内核开发相关问询
关于C语言固定长度类型与Linux内核类型定义的疑问
核心问题
- C语言规范仅对内置类型做最小长度限制:char至少8位、int至少32位、long long至少64位等,但内核架构相关代码需要长度严格固定为8/16/32/64位的类型,用于读写I/O端口或寄存器,想问是否有现成的这类类型?
- 观察Linux源码中的
u32/u64等类型是基于内置类型定义的,想知道:这些类型的长度是靠特定架构编译时的规则保证,还是通过Makefile编译选项强制固定的?
Linux内核中的固定长度类型实现
Linux内核通过头文件定义了一套专属的固定长度类型,具体实现如下:
通用底层定义(<uapi/asm-generic/int-ll64.h>)
typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; typedef __signed__ long long __s64; typedef unsigned long long __u64;
对外暴露的公共类型(<linux/asm-generic/int-ll64.h>)
typedef __s8 s8; typedef __u8 u8; typedef __s16 s16; typedef __u16 u16; typedef __s32 s32; typedef __u32 u32; typedef __s64 s64; typedef __u64 u64;
衍生的架构适配类型
比如物理地址类型phys_addr_t,会根据架构配置选择对应长度:
#ifdef CONFIG_PHYS_ADDR_T_64BIT typedef u64 phys_addr_t; #else typedef u32 phys_addr_t; #endif
问题解答
1. 固定长度的现成类型有哪些?
有两类可选:
- 标准C的
<stdint.h>类型:比如uint8_t、int32_t、uint64_t等,这是C99标准引入的固定长度类型。但要注意:它们是可选类型,仅当编译器的内置类型恰好匹配对应长度时才会提供,如果平台没有刚好符合长度的内置类型,标准库不会定义这些类型。 - Linux内核自定义的
s8/u8/s32/u32系列:这是内核为跨架构统一实现的类型,比标准库的更可靠——内核会针对每个目标架构,确保对应的内置类型长度严格符合要求,因此这些类型的长度是确定的。
2. Linux内核中这些类型的长度如何保证?
核心是目标架构的ABI(应用二进制接口)规定了内置类型的长度,而非Makefile编译选项强制固定:
- 每个架构都有自己的ABI规则,比如x86架构规定char=8位、short=16位、int=32位、long long=64位;ARM32架构同理,int固定为32位。编译器在针对该架构编译时,必须严格遵守ABI要求,因此对应的内置类型长度是确定的。
- 内核的
asm-generic/int-ll64.h是通用模板,每个架构会有自己的asm/int-ll64.h(或对应头文件)来适配本架构的ABI,确保__s8对应8位、__s32对应32位等。 - Makefile的作用只是指定编译的目标架构(比如
ARCH=x86_64),编译器会自动加载对应架构的ABI规则,从而保证内置类型的长度符合内核定义的要求。 - 像
phys_addr_t这类衍生类型,只是基于已经保证长度的s/u类型,根据架构的物理地址宽度(通过内核配置选项CONFIG_PHYS_ADDR_T_64BIT选择)来确定最终类型,本质还是依赖架构ABI的固定长度类型。
内容的提问来源于stack exchange,提问作者08822407d
相关产品推荐
相关产品推荐

