int_fast8_t 和 int_fast16_t 的区别

Jer*_* wu 5 c embedded stm32

我是嵌入式系统的初学者,我在头文件中看到int_fast8_t/int_fast16_t/int_fast32_t都是带符号的 int。那么它们之间有什么区别吗?或者它们基本相同,即使您为 int_fast8_t 分配了 32 位,它仍然会存储 32 位而不是 8 位?

    /* fastest minimum-width signed integer types */
typedef    signed            int    int_fast8_t;
typedef    signed            int    int_fast16_t;
typedef    signed            int    int_fast32_t;
typedef    signed        __INT64    int_fast64_t;
Run Code Online (Sandbox Code Playgroud)

klu*_*utt 6

这就是特定实现定义它们的方式。该标准要求的int_fast8_t至少8位。它们的目的是实现应该使用它们中最快的,但对此或如何衡量它没有严格的要求。

C11 标准 7.20.1.3

1 以下每个类型都指定一个整数类型,它通常在所有至少具有指定宽度的整数类型中最快(262)进行操作。

2 typedef 名称 int_fastN_t 指定宽度至少为 N 的最快有符号整数类型。typedef 名称 uint_fastN_t 指定宽度至少为 N 的最快的无符号整数类型。

3 需要以下类型:

    int_fast8_t                                    uint_fast8_t
    int_fast16_t                                   uint_fast16_t
    int_fast32_t                                   uint_fast32_t
    int_fast64_t                                   uint_fast64_t
Run Code Online (Sandbox Code Playgroud)

此表格的所有其他类型都是可选的。

链接的注释说:

  1. 不能保证指定的类型在所有用途中都是最快的;如果实现没有明确的理由选择一种类型而不是另一种,它只会选择一些满足符号和宽度要求的整数类型。

通常,“fast”变量被定义为目标处理器的本机大小,前提是它至少与指定的大小一样大。请注意,这取决于更快的情况。当您对单个变量进行操作时,通常最好使用本机大小,但在大型数组上,您通常需要满足您需求的最小类型,因为数组越大,原始字节数越差用于缓存。

例如,以Open Watcom for DOS为例。你有这个:

typedef signed   int       int_fast8_t;
typedef signed   int       int_fast16_t;
typedef signed   long      int_fast32_t;
typedef signed   long long int_fast64_t;
Run Code Online (Sandbox Code Playgroud)

请注意,这是 32 位和 16 位之间的区别,在您的示例中没有。

在我的 gcc 实现中,我有这个:

typedef unsigned char uint_fast8_t;
typedef unsigned long int uint_fast16_t;
typedef unsigned long int uint_fast32_t;
typedef unsigned long int uint_fast64_t;
Run Code Online (Sandbox Code Playgroud)

AFIK在几乎所有情况下的int8_t行为都完全一样int_fast8_t。但在某些情况下,您可能需要小心。看看这个程序:

#include <stdio.h>
#include <stdint.h>

int main(void) {
    int_fast16_t array[] = { 12345,23456,34567 };
    int16_t *ptr = array;
    for(int i=0; i<3; i++) {
        printf("%d %d\n", ptr[i], array[i]);
    }
}
Run Code Online (Sandbox Code Playgroud)

它给了我这个警告:

$ gcc main.c 
main.c: In function ‘main’:
main.c:6:20: warning: initialization of ‘int16_t *’ {aka ‘short int *’} from incompatible pointer type ‘int_fast16_t *’ {aka ‘long int *’} [-Wincompatible-pointer-types]
    6 |     int16_t *ptr = array;
      |                    ^~~~~
Run Code Online (Sandbox Code Playgroud)

并打印:

$ ./a.out 
12345 12345
0 23456
0 34567
Run Code Online (Sandbox Code Playgroud)

这些类型基本上分为三类:

  1. 精确宽度
  2. 最小宽度
  3. 最快最小宽度

确切的宽度必须是精确的,但另外两个具有相同的要求目的不同。

在嵌入式系统中,我会为数组选择精确的宽度,并为常规变量选择最快(或只是intlong)。如果存在精确的宽度,我真的看不出最小宽度的用处,除了便携性。在这里,我想指出标准要求最小和最快,但不需要确切的宽度。大多数系统确实支持精确宽度。因此,除非您想要 100% 的可移植性或知道您需要在不支持它的机器上编译代码的事实,否则我总是更喜欢精确宽度而不是最小宽度。