<stdint.h> 中的标准整数在编译期间如何翻译?
How are standard integers from <stdint.h> translated during compilation?
在 C 中,使用相同的源代码针对不同的处理器体系结构是很常见的(或至少是可能的)。处理器架构以不同方式定义整数大小也很常见。为了增加代码的可移植性并避免整数大小限制,建议使用 C 标准整数头。但是,我对它的实际实现方式感到困惑。
如果我正在编写一个为 x86 编写的小 C 程序,然后决定将其移植到 8 位微控制器,微控制器编译器如何知道如何将 'uint32_t' 转换为其本机整数类型?
编写C编译器时是否有一些映射要求?比如,如果你的编译器要与 C99 兼容,你需要有一个映射功能,用本地类型替换所有 uint32_t?
谢谢!
通常 <stdint.h>
包含相当于
typedef int int32_t;
typedef unsigned uint32_t;
选择适合当前机器的实际类型。
实际上它通常比这复杂得多,有许多额外的辅助 header 文件和辅助预处理器宏,但效果是一样的:像 uint32_t
这样的名字最终被真正的类型名称,就像由 typedef
.
定义的一样
你问了 "if your compiler is to be C99 compatible, you need to have a mapping feature?",答案基本上是 "yes",但是 "mapping feature" 可能只是编译器作者在其 [=14= 的分布式副本中选择的特定类型]. (要回答你的另一个问题,是的,那里的 <stdint.h>
副本至少与编译器一样多;没有一个主副本或任何东西。)
一边评论。你说,"To increase code portability and avoid integer size limitations, it is recommended to use the C standard integer header"。真正的建议是当您有特殊要求时使用 header ,例如具有精确类型 的尺寸。如果由于某种原因你需要一个有符号的类型,比如说,正好是 32 位,那么一定要使用 stdint.h
中的 int32_t
。但大多数时候,您会发现像 int
和 long
这样的 "plain" 类型是完全没问题的。请不要让任何人告诉您必须为您声明的每个变量选择一个确切的大小,并使用 stdint.h
的类型名称来声明它。
"mapping" 或 "translating" 的形式并没有什么神奇的事情发生:stdint.h
只是包含一个 typedef
语句的列表。区别在于代码生成器,而不是编译器前端。
对于 8 位目标,代码生成器将使用本机指令对其本机支持的任何类型进行算术运算(可能有 16 位加法指令)。对于其余部分,它将插入对库例程的调用以实现更大的数据类型。
8 位编译器的 RTL 包含 "long_add"、"long_subtract" 等例程的情况并不少见。
不同架构的处理很可能是通过条件预处理指令实现的,例如 #if
或 #ifdef
。例如,在 GNU/Linux 平台上它可能看起来像:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
在 C 中,使用相同的源代码针对不同的处理器体系结构是很常见的(或至少是可能的)。处理器架构以不同方式定义整数大小也很常见。为了增加代码的可移植性并避免整数大小限制,建议使用 C 标准整数头。但是,我对它的实际实现方式感到困惑。
如果我正在编写一个为 x86 编写的小 C 程序,然后决定将其移植到 8 位微控制器,微控制器编译器如何知道如何将 'uint32_t' 转换为其本机整数类型?
编写C编译器时是否有一些映射要求?比如,如果你的编译器要与 C99 兼容,你需要有一个映射功能,用本地类型替换所有 uint32_t?
谢谢!
通常 <stdint.h>
包含相当于
typedef int int32_t;
typedef unsigned uint32_t;
选择适合当前机器的实际类型。
实际上它通常比这复杂得多,有许多额外的辅助 header 文件和辅助预处理器宏,但效果是一样的:像 uint32_t
这样的名字最终被真正的类型名称,就像由 typedef
.
你问了 "if your compiler is to be C99 compatible, you need to have a mapping feature?",答案基本上是 "yes",但是 "mapping feature" 可能只是编译器作者在其 [=14= 的分布式副本中选择的特定类型]. (要回答你的另一个问题,是的,那里的 <stdint.h>
副本至少与编译器一样多;没有一个主副本或任何东西。)
一边评论。你说,"To increase code portability and avoid integer size limitations, it is recommended to use the C standard integer header"。真正的建议是当您有特殊要求时使用 header ,例如具有精确类型 的尺寸。如果由于某种原因你需要一个有符号的类型,比如说,正好是 32 位,那么一定要使用 stdint.h
中的 int32_t
。但大多数时候,您会发现像 int
和 long
这样的 "plain" 类型是完全没问题的。请不要让任何人告诉您必须为您声明的每个变量选择一个确切的大小,并使用 stdint.h
的类型名称来声明它。
"mapping" 或 "translating" 的形式并没有什么神奇的事情发生:stdint.h
只是包含一个 typedef
语句的列表。区别在于代码生成器,而不是编译器前端。
对于 8 位目标,代码生成器将使用本机指令对其本机支持的任何类型进行算术运算(可能有 16 位加法指令)。对于其余部分,它将插入对库例程的调用以实现更大的数据类型。
8 位编译器的 RTL 包含 "long_add"、"long_subtract" 等例程的情况并不少见。
不同架构的处理很可能是通过条件预处理指令实现的,例如 #if
或 #ifdef
。例如,在 GNU/Linux 平台上它可能看起来像:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif