You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为scanf("%zn")构建可移植的size_t有符号等效类型?

解决C语言中%zn适配size_t的可移植方案

核心问题

C17标准明确规定%zn格式符要求对应指向有符号整数类型的指针,而size_t是无符号类型,直接传入size_t*会触发编译器警告(如GCC 12的警告)。由于C语言没有类似C++std::make_signed_t的类型工具,可通过以下几种可移植方式处理:

方案1:临时有符号变量中转(最稳妥的标准C方案)

先声明足够宽度的有符号整数变量,用%zn存储读取的字符数,再安全转换为size_t(已读字符数不可能为负,转换无溢出风险)。

示例代码:

#include <stdio.h>

int main(void)
{
    int count;
    sscanf("abc", "%*s%zn", &count);
    size_t i = (size_t)count;
    printf("%zu", i);
    return 0;
}

若担心int宽度不足(比如64位平台下size_t为64位、int为32位),可改用intmax_t(需包含<stdint.h>),确保有符号类型宽度不小于size_t:

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

int main(void)
{
    intmax_t count;
    sscanf("abc", "%*s%zn", &count);
    size_t i = (size_t)count;
    printf("%zu", i);
    return 0;
}

方案2:用_Generic自动匹配对应有符号类型(C11及以上)

借助C11的_Generic特性,根据size_t的实际类型自动匹配同宽度的有符号类型,无需手动判断平台:

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

#define MAKE_SIGNED_SIZE_T(_var) _Generic((_var), \
    unsigned char: signed char, \
    unsigned short: short, \
    unsigned int: int, \
    unsigned long: long, \
    unsigned long long: long long, \
    uintmax_t: intmax_t)

int main(void)
{
    MAKE_SIGNED_SIZE_T(size_t{0}) count;
    sscanf("abc", "%*s%zn", &count);
    size_t i = (size_t)count;
    printf("%zu", i);
    return 0;
}

方案3:使用POSIX扩展类型ssize_t(仅适用于POSIX系统)

如果代码仅在Linux、macOS等POSIX兼容环境运行,可直接用ssize_t——它被定义为size_t的有符号等效类型:

#include <stdio.h>
#include <sys/types.h>

int main(void)
{
    ssize_t count;
    sscanf("abc", "%*s%zn", &count);
    size_t i = (size_t)count;
    printf("%zu", i);
    return 0;
}

注意:ssize_t不属于C标准,无法移植到Windows等非POSIX系统。


内容的提问来源于stack exchange,提问作者Toby Speight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 23:25:57