Skip to content

C 标准库 - <inttypes.h>

概述

<inttypes.h> 头文件扩展了 <stdint.h>,提供了用于格式化精确宽度整数类型的宏,以及整数转换函数。这是 C99 标准引入的头文件,对于跨平台编程中的格式化输出非常重要。

格式化宏

PRId8, PRIi8

int8_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int8_t value = 127;
    printf("int8_t 值: %" PRId8 "\n", value);
    printf("int8_t 值: %" PRIi8 "\n", value);
    
    return 0;
}

PRId16, PRIi16

int16_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int16_t value = 32767;
    printf("int16_t 值: %" PRId16 "\n", value);
    printf("int16_t 值: %" PRIi16 "\n", value);
    
    return 0;
}

PRId32, PRIi32

int32_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int32_t value = 2147483647;
    printf("int32_t 值: %" PRId32 "\n", value);
    printf("int32_t 值: %" PRIi32 "\n", value);
    
    return 0;
}

PRId64, PRIi64

int64_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int64_t value = 9223372036854775807LL;
    printf("int64_t 值: %" PRId64 "\n", value);
    printf("int64_t 值: %" PRIi64 "\n", value);
    
    return 0;
}

PRIu8

uint8_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint8_t value = 255;
    printf("uint8_t 值: %" PRIu8 "\n", value);
    
    return 0;
}

PRIu16

uint16_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint16_t value = 65535;
    printf("uint16_t 值: %" PRIu16 "\n", value);
    
    return 0;
}

PRIu32

uint32_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint32_t value = 4294967295U;
    printf("uint32_t 值: %" PRIu32 "\n", value);
    
    return 0;
}

PRIu64

uint64_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t value = 18446744073709551615ULL;
    printf("uint64_t 值: %" PRIu64 "\n", value);
    
    return 0;
}

PRIx8, PRIX8

uint8_t 的十六进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint8_t value = 255;
    printf("uint8_t 值: 0x%02" PRIx8 "\n", value);
    printf("uint8_t 值: 0x%02" PRIX8 "\n", value);
    
    return 0;
}

PRIx16, PRIX16

uint16_t 的十六进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint16_t value = 65535;
    printf("uint16_t 值: 0x%04" PRIx16 "\n", value);
    printf("uint16_t 值: 0x%04" PRIX16 "\n", value);
    
    return 0;
}

PRIx32, PRIX32

uint32_t 的十六进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint32_t value = 4294967295U;
    printf("uint32_t 值: 0x%08" PRIx32 "\n", value);
    printf("uint32_t 值: 0x%08" PRIX32 "\n", value);
    
    return 0;
}

PRIx64, PRIX64

uint64_t 的十六进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t value = 18446744073709551615ULL;
    printf("uint64_t 值: 0x%016" PRIx64 "\n", value);
    printf("uint64_t 值: 0x%016" PRIX64 "\n", value);
    
    return 0;
}

PRIo8

uint8_t 的八进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint8_t value = 255;
    printf("uint8_t 值: 0%03" PRIo8 "\n", value);
    
    return 0;
}

PRIo16

uint16_t 的八进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint16_t value = 65535;
    printf("uint16_t 值: 0%06" PRIo16 "\n", value);
    
    return 0;
}

PRIo32

uint32_t 的八进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint32_t value = 4294967295U;
    printf("uint32_t 值: 0%011" PRIo32 "\n", value);
    
    return 0;
}

PRIo64

uint64_t 的八进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t value = 18446744073709551615ULL;
    printf("uint64_t 值: 0%022" PRIo64 "\n", value);
    
    return 0;
}

扫描宏

SCNd8, SCNi8

int8_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int8_t value;
    printf("输入 int8_t 值: ");
    scanf("%" SCNd8, &value);
    printf("输入的值: %" PRId8 "\n", value);
    
    return 0;
}

SCNd16, SCNi16

int16_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int16_t value;
    printf("输入 int16_t 值: ");
    scanf("%" SCNd16, &value);
    printf("输入的值: %" PRId16 "\n", value);
    
    return 0;
}

SCNd32, SCNi32

int32_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int32_t value;
    printf("输入 int32_t 值: ");
    scanf("%" SCNd32, &value);
    printf("输入的值: %" PRId32 "\n", value);
    
    return 0;
}

SCNd64, SCNi64

int64_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int64_t value;
    printf("输入 int64_t 值: ");
    scanf("%" SCNd64, &value);
    printf("输入的值: %" PRId64 "\n", value);
    
    return 0;
}

SCNu8

uint8_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint8_t value;
    printf("输入 uint8_t 值: ");
    scanf("%" SCNu8, &value);
    printf("输入的值: %" PRIu8 "\n", value);
    
    return 0;
}

SCNu16

uint16_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint16_t value;
    printf("输入 uint16_t 值: ");
    scanf("%" SCNu16, &value);
    printf("输入的值: %" PRIu16 "\n", value);
    
    return 0;
}

SCNu32

uint32_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint32_t value;
    printf("输入 uint32_t 值: ");
    scanf("%" SCNu32, &value);
    printf("输入的值: %" PRIu32 "\n", value);
    
    return 0;
}

SCNu64

uint64_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t value;
    printf("输入 uint64_t 值: ");
    scanf("%" SCNu64, &value);
    printf("输入的值: %" PRIu64 "\n", value);
    
    return 0;
}

最大宽度类型宏

PRIdMAX, PRIiMAX

intmax_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    intmax_t value = 9223372036854775807LL;
    printf("intmax_t 值: %" PRIdMAX "\n", value);
    printf("intmax_t 值: %" PRIiMAX "\n", value);
    
    return 0;
}

PRIuMAX

uintmax_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uintmax_t value = 18446744073709551615ULL;
    printf("uintmax_t 值: %" PRIuMAX "\n", value);
    
    return 0;
}

PRIxMAX, PRIXMAX

uintmax_t 的十六进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uintmax_t value = 18446744073709551615ULL;
    printf("uintmax_t 值: 0x%016" PRIxMAX "\n", value);
    printf("uintmax_t 值: 0x%016" PRIXMAX "\n", value);
    
    return 0;
}

SCNdMAX, SCNiMAX

intmax_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    intmax_t value;
    printf("输入 intmax_t 值: ");
    scanf("%" SCNdMAX, &value);
    printf("输入的值: %" PRIdMAX "\n", value);
    
    return 0;
}

SCNuMAX

uintmax_t 的扫描宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uintmax_t value;
    printf("输入 uintmax_t 值: ");
    scanf("%" SCNuMAX, &value);
    printf("输入的值: %" PRIuMAX "\n", value);
    
    return 0;
}

指针类型宏

PRIdPTR, PRIiPTR

intptr_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    intptr_t value = 12345;
    printf("intptr_t 值: %" PRIdPTR "\n", value);
    printf("intptr_t 值: %" PRIiPTR "\n", value);
    
    return 0;
}

PRIuPTR

uintptr_t 的格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uintptr_t value = 12345;
    printf("uintptr_t 值: %" PRIuPTR "\n", value);
    
    return 0;
}

PRIxPTR, PRIXPTR

uintptr_t 的十六进制格式化宏。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    uintptr_t value = 0x12345678;
    printf("uintptr_t 值: 0x%08" PRIxPTR "\n", value);
    printf("uintptr_t 值: 0x%08" PRIXPTR "\n", value);
    
    return 0;
}

整数转换函数

imaxabs()

c
intmax_t imaxabs(intmax_t j);

计算 intmax_t 的绝对值。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    intmax_t value = -12345;
    intmax_t abs_value = imaxabs(value);
    
    printf("原始值: %" PRIdMAX "\n", value);
    printf("绝对值: %" PRIdMAX "\n", abs_value);
    
    return 0;
}

imaxdiv()

c
imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom);

intmax_t 的整数除法。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    intmax_t numer = 12345;
    intmax_t denom = 67;
    
    imaxdiv_t result = imaxdiv(numer, denom);
    
    printf("%" PRIdMAX " / %" PRIdMAX " = %" PRIdMAX "\n", 
           numer, denom, result.quot);
    printf("%" PRIdMAX " %% %" PRIdMAX " = %" PRIdMAX "\n", 
           numer, denom, result.rem);
    
    return 0;
}

strtoimax()

c
intmax_t strtoimax(const char *nptr, char **endptr, int base);

字符串转换为 intmax_t。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    const char* str = "1234567890";
    char* endptr;
    
    intmax_t value = strtoimax(str, &endptr, 10);
    
    printf("字符串: %s\n", str);
    printf("转换值: %" PRIdMAX "\n", value);
    printf("剩余字符串: %s\n", endptr);
    
    return 0;
}

strtoumax()

c
uintmax_t strtoumax(const char *nptr, char **endptr, int base);

字符串转换为 uintmax_t。

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    const char* str = "18446744073709551615";
    char* endptr;
    
    uintmax_t value = strtoumax(str, &endptr, 10);
    
    printf("字符串: %s\n", str);
    printf("转换值: %" PRIuMAX "\n", value);
    printf("剩余字符串: %s\n", endptr);
    
    return 0;
}

wcstoimax()

c
intmax_t wcstoimax(const wchar_t *nptr, wchar_t **endptr, int base);

宽字符串转换为 intmax_t。

c
#include <stdio.h>
#include <wchar.h>
#include <inttypes.h>

int main() {
    const wchar_t* wstr = L"1234567890";
    wchar_t* endptr;
    
    intmax_t value = wcstoimax(wstr, &endptr, 10);
    
    printf("转换值: %" PRIdMAX "\n", value);
    
    return 0;
}

wcstoumax()

c
uintmax_t wcstoumax(const wchar_t *nptr, wchar_t **endptr, int base);

宽字符串转换为 uintmax_t。

c
#include <stdio.h>
#include <wchar.h>
#include <inttypes.h>

int main() {
    const wchar_t* wstr = L"18446744073709551615";
    wchar_t* endptr;
    
    uintmax_t value = wcstoumax(wstr, &endptr, 10);
    
    printf("转换值: %" PRIuMAX "\n", value);
    
    return 0;
}

实际应用示例

1. 跨平台日志

c
#include <stdio.h>
#include <inttypes.h>
#include <time.h>

void log_message(const char* level, const char* message, intmax_t value) {
    time_t now = time(NULL);
    struct tm* tm = localtime(&now);
    
    printf("[%04d-%02d-%02d %02d:%02d:%02d] [%s] %s: %" PRIdMAX "\n",
           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec,
           level, message, value);
}

int main() {
    log_message("INFO", "处理数据", 12345);
    log_message("DEBUG", "内存使用", 65536);
    log_message("ERROR", "错误代码", -1);
    
    return 0;
}

2. 网络协议解析

c
#include <stdio.h>
#include <inttypes.h>

typedef struct {
    uint32_t sequence;
    uint32_t timestamp;
    uint16_t length;
    uint8_t flags;
} PacketHeader;

void print_packet_header(const PacketHeader* header) {
    printf("序列号: %" PRIu32 "\n", header->sequence);
    printf("时间戳: %" PRIu32 "\n", header->timestamp);
    printf("长度: %" PRIu16 "\n", header->length);
    printf("标志: 0x%02" PRIx8 "\n", header->flags);
}

int main() {
    PacketHeader header = {
        .sequence = 1234567890,
        .timestamp = 1704067200,
        .length = 1024,
        .flags = 0x0F
    };
    
    print_packet_header(&header);
    
    return 0;
}

3. 文件大小显示

c
#include <stdio.h>
#include <inttypes.h>

void print_file_size(uintmax_t size) {
    const char* units[] = {"B", "KB", "MB", "GB", "TB"};
    int unit_index = 0;
    double display_size = size;
    
    while (display_size >= 1024 && unit_index < 4) {
        display_size /= 1024;
        unit_index++;
    }
    
    printf("文件大小: %.2f %s (%" PRIuMAX " 字节)\n", 
           display_size, units[unit_index], size);
}

int main() {
    print_file_size(1024);
    print_file_size(1048576);
    print_file_size(1073741824);
    print_file_size(1099511627776ULL);
    
    return 0;
}

4. 内存地址显示

c
#include <stdio.h>
#include <inttypes.h>

void print_pointer(void* ptr) {
    uintptr_t address = (uintptr_t)ptr;
    printf("指针地址: 0x%016" PRIxPTR "\n", address);
}

int main() {
    int value = 42;
    int* ptr = &value;
    
    print_pointer(ptr);
    
    return 0;
}

5. 十六进制转储

c
#include <stdio.h>
#include <inttypes.h>

void hex_dump(const uint8_t* data, size_t size) {
    for (size_t i = 0; i < size; i++) {
        printf("%02" PRIx8 " ", data[i]);
        if ((i + 1) % 16 == 0) {
            printf("\n");
        }
    }
    printf("\n");
}

int main() {
    uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                      0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
    
    hex_dump(data, sizeof(data));
    
    return 0;
}

6. 大数计算

c
#include <stdio.h>
#include <inttypes.h>

uintmax_t factorial(uint8_t n) {
    if (n == 0 || n == 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

int main() {
    for (uint8_t i = 0; i <= 20; i++) {
        printf("%" PRIu8 "! = %" PRIuMAX "\n", i, factorial(i));
    }
    
    return 0;
}

7. 时间戳转换

c
#include <stdio.h>
#include <inttypes.h>
#include <time.h>

void print_timestamp(uint32_t timestamp) {
    time_t t = timestamp;
    struct tm* tm = localtime(&t);
    
    printf("时间戳: %" PRIu32 "\n", timestamp);
    printf("时间: %04d-%02d-%02d %02d:%02d:%02d\n",
           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec);
}

int main() {
    print_timestamp(1704067200);
    print_timestamp(1704153600);
    
    return 0;
}

8. 配置文件解析

c
#include <stdio.h>
#include <inttypes.h>
#include <string.h>

void parse_config_line(const char* line) {
    char key[100];
    char value[100];
    
    if (sscanf(line, "%99[^=]=%99s", key, value) == 2) {
        if (strcmp(key, "max_size") == 0) {
            uintmax_t max_size = strtoumax(value, NULL, 10);
            printf("max_size = %" PRIuMAX "\n", max_size);
        } else if (strcmp(key, "timeout") == 0) {
            intmax_t timeout = strtoimax(value, NULL, 10);
            printf("timeout = %" PRIdMAX "\n", timeout);
        }
    }
}

int main() {
    parse_config_line("max_size=1048576");
    parse_config_line("timeout=30");
    
    return 0;
}

9. 位操作

c
#include <stdio.h>
#include <inttypes.h>

void print_bits(uint32_t value) {
    for (int i = 31; i >= 0; i--) {
        printf("%" PRIu32, (value >> i) & 1);
        if (i % 8 == 0 && i != 0) {
            printf(" ");
        }
    }
    printf("\n");
}

int main() {
    uint32_t value = 0x12345678;
    
    printf("值: 0x%08" PRIx32 "\n", value);
    printf("二进制: ");
    print_bits(value);
    
    return 0;
}

10. 版本号比较

c
#include <stdio.h>
#include <inttypes.h>
#include <string.h>

typedef struct {
    uint16_t major;
    uint16_t minor;
    uint16_t patch;
} Version;

int compare_versions(const Version* v1, const Version* v2) {
    if (v1->major != v2->major) {
        return v1->major > v2->major ? 1 : -1;
    }
    if (v1->minor != v2->minor) {
        return v1->minor > v2->minor ? 1 : -1;
    }
    if (v1->patch != v2->patch) {
        return v1->patch > v2->patch ? 1 : -1;
    }
    return 0;
}

void print_version(const Version* v) {
    printf("版本: %" PRIu16 ".%" PRIu16 ".%" PRIu16 "\n",
           v->major, v->minor, v->patch);
}

int main() {
    Version v1 = {1, 2, 3};
    Version v2 = {1, 2, 4};
    Version v3 = {1, 2, 3};
    
    print_version(&v1);
    print_version(&v2);
    
    printf("v1 vs v2: %d\n", compare_versions(&v1, &v2));
    printf("v1 vs v3: %d\n", compare_versions(&v1, &v3));
    
    return 0;
}

注意事项

1. 格式化字符串拼接

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int32_t value = 123456789;
    
    printf("正确方式: %" PRId32 "\n", value);
    
    return 0;
}

2. 扫描宏的使用

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int32_t value;
    
    printf("输入值: ");
    scanf("%" SCNd32, &value);
    printf("输入的值: %" PRId32 "\n", value);
    
    return 0;
}

3. 跨平台兼容性

c
#include <stdio.h>
#include <inttypes.h>

int main() {
    int32_t value = 123456789;
    
    printf("int32_t 值: %" PRId32 "\n", value);
    printf("int32_t 值: 0x%08" PRIx32 "\n", value);
    printf("int32_t 值: 0%011" PRIo32 "\n", value);
    
    return 0;
}

4. 错误处理

c
#include <stdio.h>
#include <inttypes.h>
#include <errno.h>
#include <stdlib.h>

int main() {
    const char* str = "123456789012345678901234567890";
    char* endptr;
    
    errno = 0;
    uintmax_t value = strtoumax(str, &endptr, 10);
    
    if (errno == ERANGE) {
        printf("值超出范围\n");
    } else {
        printf("转换值: %" PRIuMAX "\n", value);
    }
    
    return 0;
}

总结

<inttypes.h> 提供的格式化宏和转换函数对于跨平台编程非常重要:

  1. 跨平台兼容 - 确保在不同平台上正确格式化整数类型
  2. 类型安全 - 使用正确的格式化宏避免未定义行为
  3. 易于使用 - 提供了简单直观的接口
  4. 广泛应用 - 适用于网络协议、文件格式、日志等场景

记住:

  • 始终使用格式化宏而不是硬编码的格式字符串
  • 注意格式化字符串的正确拼接
  • 使用扫描宏进行输入
  • 检查转换函数的错误
  • 根据需求选择合适的整数类型