【问题标题】:Parse human-readable sizes (k, M, G, T) into bytes in C将人类可读的大小(k、M、G、T)解析为 C 中的字节
【发布时间】:2013-04-13 00:33:54
【问题描述】:

我正在寻找一种将人类可读的字节大小(例如:100、1k、2M、4G)解析为字节值的快速方法。输入是 char *,输出必须是 size_t(例如,无符号,可能是 64 位或 32 位整数,具体取决于架构)。代码应该检测到无效输入并返回一个表明它是无效输入的值。

例子:

Input  => size_t result
-----------------------
"100"  => 100
"10k"  => 10240
"2M"   => 2097152
"4G"   => 4294967296 on 64-bit machine, error (overflow) on 32-bit machine
"ten"  => error

下面是一个示例代码片段,可以扩展以处理单元前缀:

int parse_human_readable_byte_size(char *input, size_t *result) {
    /* TODO: needs to support k, M, G, etc... */
    return sscanf("%zu", result) == 1;
}

以下是一些附加要求:

  • 必须用 C(非 C++)完成
  • 仅使用标准库(或至少常用的)库(例如sscanfatoi

预计代码在每次程序执行时只运行几次,因此更小的可读代码比更长的高性能代码更受青睐。

【问题讨论】:

  • 似乎不是一个明智的解决方案,但也许您可以尝试size_t array_t[2] 并将大数字分成两半
  • 嗨 SuvP,这并不意味着我上面的代码 sn-p 是一个有效的解决方案——只是为了提供代码需要做什么的示例。实际的解决方案可以是任何(类似的)形式。
  • 我的意思是我的建议并没有找到一个明智的解决方案

标签: c parsing scanf atoi


【解决方案1】:

这是一个潜在的实现。包括检测所有错误的代码;如果您愿意,请填写您自己的处理方式来代替gotos。

char *endp = s;
int sh;
errno = 0;
uintmax_t x = strtoumax(s, &endp, 10);
if (errno || endp == s) goto error;
switch(*endp) {
case 'k': sh=10; break;
case 'M': sh=20; break;
case 'G': sh=30; break;
case 0: sh=0; break;
default: goto error;
}
if (x > SIZE_MAX>>sh) goto error;
x <<= sh;

【讨论】:

  • 非常好。我认为它需要在切换 if (sh &amp;&amp; endp[1]) goto error; 之后添加一点点来处理末尾带有额外字符的输入。
【解决方案2】:

我将尝试使用一个按字符分析输入字符的子函数。

进一步进行明显的错误检查,我将使其转换数字常量中的符号,乘以对应于常量的基数。

【讨论】:

    【解决方案3】:

    根据接受的答案,我更新了截图。 支持浮点输入(如1.5k),支持十六进制输入(如0x55k),删除gotos,并使用字符串作为单位列表,避免切换,方便更新。

    static char *human_readable_suffix = "kMGT";
    
    size_t *parse_human_readable(char *input, size_t *target) {
        char *endp = input;
        char *match = NULL;
        size_t shift = 0;
        errno = 0;
    
        long double value = strtold(input, &endp);
        if(errno || endp == input || value < 0)
            return NULL;
    
        if(!(match = strchr(human_readable_suffix, *endp)))
            return NULL;
    
        if(*match)
            shift = (match - human_readable_suffix + 1) * 10;
    
        *target = value * (1LU << shift);
    
        return target;
    }
    

    这是测试结果:

    1337   =>           1337 [ok, expected: 1337]
    857.54 =>            857 [ok, expected: 857]
    128k   =>         131072 [ok, expected: 131072]
    1.5k   =>           1536 [ok, expected: 1536]
    8M     =>        8388608 [ok, expected: 8388608]
    0x55   =>             85 [ok, expected: 85]
    0x55k  =>          87040 [ok, expected: 87040]
    1T     =>  1099511627776 [ok, expected: 1099511627776]
    32.    =>             32 [ok, expected: 32]
    -87    => error (expected)
    abcd   => error (expected)
    32x    => error (expected)
    

    完整代码见:https://gist.github.com/maxux/786a9b8bf55fb0696f7e31b8fa3f6b9d

    【讨论】:

      猜你喜欢
      • 2017-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多