跨平台支持sprintf的格式'-Flag [英] Cross Platform Support for sprintf's Format '-Flag

查看:185
本文介绍了跨平台支持sprintf的格式'-Flag的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

单UNIX规范版本2 指定了sprintf'-标志行为的格式设置为:

The Single UNIX Specification Version 2 specifies the sprintf's format '-flag behavior as:

十进制转换结果的整数部分(%i%d%u%f%g%G)将使用成千上万个分组字符进行格式化 [ 1 ]

The integer portion of the result of a decimal conversion (%i, %d, %u, %f, %g or %G) will be formatted with thousands' grouping characters[1]

我在规范. g ++甚至会警告:

I can't find the format '-flag in the c or the c++ specifications. g++ even warns:

ISO C ++ 11不支持' printf标志

在Visual C中甚至无法警告该标志; printf("%'d", foo)输出:

The flag is not recognized to even warn about in Visual C; printf("%'d", foo) outputs:

'd

我希望能够编写使用格式为' -flag的行为的符合C标准的代码.因此,我正在寻找以下之一的答案:

I'd like to be able to write C-standard compliant code that uses the behavior of the format '-flag. Thus the answer I'm looking for one of the following:

  1. ' -flag
  2. 格式的C标准规范
  3. gcc格式' -flag
  4. 的跨平台兼容外推
  5. 证明无法进行跨平台推断
  1. C-Standard specification of the format '-flag
  2. A cross platform compatible extrapolation of gcc's format '-flag
  3. Demonstration that a cross platform extrapolation is not possible

推荐答案

标准C不直接提供格式设置功能,但确实提供了检索...格式设置规范的功能.特定于语言环境的基础.因此,取决于您检索适当格式的语言环境规范,然后将其用于格式化数据(但即使如此,它还是有些琐碎的).例如,这是格式化long数据的版本:

Standard C doesn't provide the formatting capability directly, but it does provide the ability to retrieve a...specification of what the formatting should be, on a locale-specific basis. So, it's up to you to retrieve the locale's specification of proper formatting, then put it to use to format your data (but even then, it's somewhat non-trivial). For example, here's a version for formatting long data:

#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <limits.h>

static int next_group(char const **grouping) {
    if ((*grouping)[1] == CHAR_MAX)
        return 0;
    if ((*grouping)[1] != '\0')
        ++*grouping;
    return **grouping;
}

size_t commafmt(char   *buf,            /* Buffer for formatted string  */
                int     bufsize,        /* Size of buffer               */
                long    N)              /* Number to convert            */
{
    int i;
    int len = 1;
    int posn = 1;
    int sign = 1;
    char *ptr = buf + bufsize - 1;

    struct lconv *fmt_info = localeconv();
    char const *tsep = fmt_info->thousands_sep;
    char const *group = fmt_info->grouping;
    // char const *neg = fmt_info->negative_sign;
    size_t sep_len = strlen(tsep);
    size_t group_len = strlen(group);
    // size_t neg_len = strlen(neg);
    int places = (int)*group;

    if (bufsize < 2)
    {
ABORT:
        *buf = '\0';
        return 0;
    }

    *ptr-- = '\0';
    --bufsize;
    if (N < 0L)
    {
        sign = -1;
        N = -N;
    }

    for ( ; len <= bufsize; ++len, ++posn)
    {
        *ptr-- = (char)((N % 10L) + '0');
        if (0L == (N /= 10L))
            break;
        if (places && (0 == (posn % places)))
        {
            places = next_group(&group);
            for (int i=sep_len; i>0; i--) {
                *ptr-- = tsep[i-1];
                if (++len >= bufsize)
                    goto ABORT;
            }
        }
        if (len >= bufsize)
            goto ABORT;
    }

    if (sign < 0)
    {
        if (len >= bufsize)
            goto ABORT;
        *ptr-- = '-';
        ++len;
    }

    memmove(buf, ++ptr, len + 1);
    return (size_t)len;
}

#ifdef TEST
#include <stdio.h>

#define elements(x) (sizeof(x)/sizeof(x[0]))

void show(long i) {
    char buffer[32];

    commafmt(buffer, sizeof(buffer), i);
    printf("%s\n", buffer);
    commafmt(buffer, sizeof(buffer), -i);
    printf("%s\n", buffer);
}


int main() {

    long inputs[] = {1, 12, 123, 1234, 12345, 123456, 1234567, 12345678 };

    for (int i=0; i<elements(inputs); i++) {
        setlocale(LC_ALL, "");
        show(inputs[i]);
    }
    return 0;
}

#endif

这确实有一个错误(但是我认为这个错误很小).在二进制补码硬件上,它将无法正确转换最负数,因为它尝试使用N = -N;将负数转换为等效的正数.在二进制补码中,最大负数没有对应的正数,除非将其提升为更大的类型.解决此问题的一种方法是通过将数字升为相应的无符号类型(但这有点不简单).

This does have a bug (but one I'd consider fairly minor). On two's complement hardware, it won't convert the most-negative number correctly, because it attempts to convert a negative number to its equivalent positive number with N = -N; In two's complement, the maximally negative number doesn't have a corresponding positive number, unless you promote it to a larger type. One way to get around this is by promoting the number the corresponding unsigned type (but it's is somewhat non-trivial).

对于其他整数类型实施相同的操作相当简单.对于浮点类型,还有更多工作要做.正确地转换浮点类型(即使没有格式化)对于他们来说也足以完成更多的工作,我至少考虑使用sprintf之类的东西进行转换,然后将格式插入所产生的字符串中.

Implementing the same for other integer types is fairly trivial. For floating point types is a bit more work. Converting floating point types (even without formatting) correctly is enough more work that for them, I'd at least consider using something like sprintf to do the conversion, then inserting the formatting into the string that produced.

这篇关于跨平台支持sprintf的格式'-Flag的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆