程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

[Linux C/C++]掌握uint8_t/uint16_t/uint32_t/uint64_t数据类型

balukai 2025-01-05 15:44:52 文章精选 8 ℃

什么是uint8_t/uint16_t/uint32_t/uint64_t数据类型?

uint8_t, uint16_t, uint32_t, 和 uint64_t 是C和C++编程语言中定义的无符号整数类型,它们分别代表8位、16位、32位和64位的无符号整数。这些类型在 <cstdint>(C++)或 <stdint.h>(C)头文件中定义,确保在不同的平台和编译器上都具有一致的大小和范围。

uint8_t

  • 定义:uint8_t 是一个无符号8位整数类型,也就是说它可以表示从0到255(即 2^8 - 1)的整数值。
  • 用途:uint8_t 通常用于需要存储单个字节的数据的场景,比如字符编码(如ASCII)或图像处理中的像素值。

uint16_t

  • 定义:uint16_t 是一个无符号16位整数类型,可以表示从0到65,535(即 2^16 - 1)的整数值。
  • 用途:uint16_t 常用于需要比8位更多但不需要32位或64位的数据的场景,比如某些协议中的数据包标识符或计数器等。

uint32_t

  • 定义:uint32_t 是一个无符号32位整数类型,可以表示从0到4,294,967,295(即 2^32 - 1)的整数值。
  • 用途:uint32_t 常用于需要精确表示32位整数大小的情况,如文件大小、网络协议中的数据包大小、时间戳等。

uint64_t

  • 定义:uint64_t 是一个无符号64位整数类型,可以表示从0到18,446,744,073,709,551,615(即 2^64 - 1)的整数值。
  • 用途:uint64_t 常用于需要存储非常大整数值的场景,如大数计算、高精度时间戳、大型数据集的大小等。

什么是int8_t/int16_t/int32_t/int64_t数据类型?

int8_t、int16_t、int32_t 和 int64_t 是C和C++编程语言中定义的带符号整数类型,分别代表8位、16位、32位和64位的带符号整数。这些类型也在 <cstdint>(C++)或 <stdint.h>(C)头文件中定义,以确保在不同的平台和编译器上都具有一致的大小和范围。

int8_t

  • 定义:int8_t 是一个带符号8位整数类型,可以表示从-128到127的整数值(即 -2^7 到 2^7 - 1)。
  • 用途:通常用于需要存储单个字节的带符号数据的场景,如某些特定的硬件操作或优化内存使用。

int16_t

  • 定义:int16_t 是一个带符号16位整数类型,可以表示从-32,768到32,767的整数值(即 -2^15 到 2^15 - 1)。
  • 用途:常用于需要比8位更多信息但不需要32位或64位的场景,比如某些协议中的数据包标识符或带符号的计数器。

int32_t

  • 定义:int32_t 是一个带符号32位整数类型,可以表示从-2,147,483,648到2,147,483,647的整数值(即 -2^31 到 2^31 - 1)。
  • 用途:常用于需要精确表示32位带符号整数大小的场景,如文件大小、网络协议中的数据包大小、时间戳等。int32_t 是由C99标准定义的,确保了它的大小为32位。

int64_t

  • 定义:int64_t 是一个带符号64位整数类型,可以表示从-9,223,372,036,854,775,808到9,223,372,036,854,775,807的整数值(即 -2^63 到 2^63 - 1)。
  • 用途:常用于需要存储非常大的带符号整数值的场景,如大数计算、高精度时间戳、大型数据集的大小等。int64_t 也是由C99标准定义的,确保了它的大小为64位。

这些数据类型是如何定义的?

在/usr/include/stdint.h中如下内容:

/* Signed. */
#include <bits/stdint-intn.h>
/* Unsigned. */
#include <bits/stdint-uintn.h>

在/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h中:

typedef __uint8_t uint8_t;
typedef __uint16_t uint16_t;
typedef __uint32_t uint32_t;
typedef __uint64_t uint64_t;

在/usr/include/x86_64-linux-gnu/bits/stdint-intn.h中:

typedef __int8_t int8_t;
typedef __int16_t int16_t;
typedef __int32_t int32_t;
typedef __int64_t int64_t;

在/usr/include/x86_64-linux-gnu/bits/types.h中:

/* Fixed-size types, underlying types depend on word size and compiler. */
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;
typedef signed int __int32_t;
typedef unsigned int __uint32_t;
typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;

所以可以得到如下定义:

无符号类型:

typedef signed char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;

有符号类型:

typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long int int64_t;

如何使用这些数据类型?

在C和C++中,你可以通过包含 <cstdint>(C++)或 <stdint.h>(C)头文件来使用这些类型。

例1: 在C程序中使用符号数据类型

[root:~/work/mytest]# cat int.c 
#include <stdio.h>  
#include <stdint.h>  
  
int main() {  
    // 使用 int8_t 类型声明一个变量  
    int8_t small_int = 10;  
    printf("small_int: %d\n", small_int);  
  
    // 使用 int16_t 类型声明一个变量  
    int16_t medium_int = 30000;  
    printf("medium_int: %d\n", medium_int);  
  
    // 使用 int32_t 类型声明一个变量  
    int32_t large_int = 2147483647; // 32位整数的最大值  
    printf("large_int: %d\n", large_int);  
  
    // 使用 int64_t 类型声明一个变量  
    int64_t very_large_int = 9223372036854775807LL; // 64位整数的最大值,注意LL后缀表示长长整数  
    printf("very_large_int: %lld\n", very_large_int);  
  
    // 使用这些类型进行数学运算  
    int32_t sum = large_int + medium_int + small_int;  
    printf("Sum: %d\n", sum);  
  
    // 注意:如果运算结果超出了变量的表示范围,可能会导致溢出  
    // 例如,下面的运算将导致溢出,因为结果超出了int32_t的表示范围  
    int32_t overflow = large_int + (int32_t)very_large_int;  
    printf("Overflow: %d\n", overflow); // 这里的输出可能不是预期的结果,因为发生了溢出  
  
    return 0;  
}
[root:~/work/mytest]#

编译并运行:

[root:~/work/mytest]# gcc -w int.c

[root:~/work/mytest]# ./a.out

small_int: 10

medium_int: 30000

large_int: 2147483647

very_large_int: 9223372036854775807

Sum: -2147453639

Overflow: 2147483646

[root:~/work/mytest]#

例2: 在C程序中使用无符号数据类型

[root:~/work/mytest]# cat uint.c
#include <stdio.h>
#include <stdint.h>

int main() {
// 使用 uint8_t 类型声明一个变量
uint8_t small_value = 25;
printf("small_value: %u\n", small_value);

// 使用 uint16_t 类型声明一个变量
uint16_t medium_value = 65530; // 接近16位无符号整数的最大值
printf("medium_value: %u\n", medium_value);

// 使用 uint32_t 类型声明一个变量
uint32_t large_value = 4294967295U; // 32位无符号整数的最大值
printf("large_value: %u\n", large_value);

// 使用 uint64_t 类型声明一个变量
uint64_t very_large_value = 18446744073709551615ULL; // 64位无符号整数的最大值
printf("very_large_value: %llu\n", very_large_value);

// 使用这些类型进行数学运算
uint64_t sum = small_value + medium_value + large_value + very_large_value;
printf("Sum: %llu\n", sum);

// 注意:无符号整数不会发生负数溢出,但会回绕到最大值
// 例如,下面的运算会导致回绕
uint32_t overflow = large_value + 1;
printf("Overflow: %u\n", overflow); // 这里的输出将是0,因为发生了回绕

return 0;
}

编译并运行:

[root:~/work/mytest]# gcc -w uint.c

[root:~/work/mytest]# ./a.out

small_value: 25

medium_value: 65530

large_value: 4294967295

very_large_value: 18446744073709551615

Sum: 65553

Overflow: 0

[root:~/work/mytest]#

例3: 在C++程序中使用无符号数据类型

[root:~/work/mytest]# cat uint.cpp 
#include <iostream>  
#include <cstdint>  
  
int main() {  
    // 使用 uint8_t 类型声明一个变量  
    uint8_t byteValue = 25;  
    std::cout << "byteValue: " << byteValue << std::endl;  
  
    // 使用 uint16_t 类型声明一个变量  
    uint16_t wordValue = 65530; // 接近16位无符号整数的最大值  
    std::cout << "wordValue: " << wordValue << std::endl;  
  
    // 使用 uint32_t 类型声明一个变量  
    uint32_t dwordValue = 4294967295U; // 32位无符号整数的最大值  
    std::cout << "dwordValue: " << dwordValue << std::endl;  
  
    // 使用 uint64_t 类型声明一个变量  
    uint64_t qwordValue = 18446744073709551615ULL; // 64位无符号整数的最大值  
    std::cout << "qwordValue: " << qwordValue << std::endl;  
  
    // 使用这些类型进行数学运算  
    uint64_t sum = byteValue + wordValue + dwordValue + qwordValue;  
    std::cout << "Sum: " << sum << std::endl;  
  
    // 注意:无符号整数不会发生负数溢出,但会回绕到最大值  
    // 例如,下面的运算会导致回绕  
    uint32_t overflow = dwordValue + 1;  
    std::cout << "Overflow: " << overflow << std::endl; // 这里的输出将是0,因为发生了回绕  
  
    return 0;  
}
[root:~/work/mytest]#

编译并运行:

[root:~/work/mytest]# g++ uint.cpp

[root:~/work/mytest]# ./a.out

byteValue:

wordValue: 65530

dwordValue: 4294967295

qwordValue: 18446744073709551615

Sum: 65553

Overflow: 0

[root:~/work/mytest]#

为什么要使用这些数据类型 或者 使用这些数据类型有什么好处?

  • 上面这些类型的定义确保了无论在哪里编译代码,这些类型总是具有相同的大小和范围,从而提供了跨平台编程的一致性。
  • 使用这些固定宽度的类型还可以提高代码的可读性和可维护性,因为它们清楚地表示了数据的大小和范围。
最近发表
标签列表