字符串中带前导零的填充在Solaris中有效,但在RHEL中则无效

时间:2017-10-24 05:16:45

标签: c linux string printf solaris

此程序在一个平台上打印带有前导0的字符串,而不是另一个平台。

<!-- JSPC servlet mappings start -->
<!-- Disabling the index_jsp servlet
<servlet>
<servlet-name>org.apache.jsp.index_jsp</servlet-name>
<servlet-class>org.apache.jsp.index_jsp</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>org.apache.jsp.index_jsp</servlet-name>
<url-pattern>/index.jsp</url-pattern>
</servlet-mapping>
-->
<!-- JSPC servlet mappings end -->

输出:

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

int main(void)
{
   char test[20];
   char a[4]="a12";
   sprintf(test,"%019s\n",a);
   printf("%s\n",test);
   return 0;
}

如何在两个平台上获得前导零?

3 个答案:

答案 0 :(得分:5)

您在两个系统上调用未定义的行为;你获得不同结果的结果并不令人惊讶。

prinf()的POSIX规范说:

  

0
      对于diouxXaA,{ {1}},eEfFg转换说明符,前导零(跟随符号或基数的任何指示)是用于填充场宽而不是执行空间填充,除非转换无穷大或NaN。如果&#39; G&#39;和&#39; 0&#39;标志都出现,&#39; -&#39;标志被忽略。对于0dioux转换说明符,如果指定了精度,则为&#39 ; X&#39;旗帜应予以忽略。 [CX]⌦如果&#39; 0&#39;并且出现0个标志,在零填充之前插入分组字符。对于其他转换,行为未定义。 ⌫

(关于解析该声明的注意事项。&#39;⌫&#39;的出现表明&#39;其他转换&#39;评论仅适用于<apostrophe>和{{ 1}}出现在一起。但是,检查C11标准(ISO / IEC 9899:2011),它说:

  

0
   对于'0diouxX,{ {1}},aAeEf次转化,前导零   (在任何符号或基础的指示之后)用于填充场宽度   而不是在执行空间填充时,除非转换无穷大或NaN。如果   出现Fg标志,忽略G标志。对于0-0dio   转换,如果指定了精度,则忽略u标志。对于其他   转换时,行为未定义。

我认为结束标记&#39;⌫&#39;错误地放在POSIX材料中。)

因此,为了获得可靠的行为,您必须更具创造性。第一步是从格式字符串中删除x

您还需要增加缓冲区的大小;你的写作超越了结束。

可能是这样的:

X

输出:

0

如果您需要在一行中处理多个值,每个值都需要填零,有多种方法可以处理它。一个选项是这样的(在所有字段大小相同的情况下简化用例):

0

输出结果为:

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

int main(void)
{
    char test[25];
    char a[4] = "a12";
    snprintf(test, sizeof(test), "%19s\n", a);
    size_t leading_blanks = strspn(test, " ");
    memset(test, '0', leading_blanks);
    printf("%s", test);
    return 0;
}

您可以小心创建更精细的格式:

0000000000000000a12

输出:

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

int main(void)
{
    char buffer[128];
    char *data[] = { "a12", "syzygy.sv.example.com", "192.168.234.119", "Quasimodo" };
    snprintf(buffer, sizeof(buffer), "%20.20s%20.20s%20.20s%20.20s",
             data[0], data[1], data[2], data[3]);
    for (int i = 0; i < 4; i++)
    {
        size_t leading_blanks = strspn(&buffer[20*i], " ");
        memset(&buffer[20*i], '0', leading_blanks);
    }
    printf("%s\n", buffer);
    return 0;
}

答案 1 :(得分:0)

您可以尝试以下内容:

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

int main()
{
    char a[4]="a12";
    int i;
    for (i = 0; i < (19 - strlen(a)); i++)
        putchar('0');
    printf("%s\n",a);
    return 0;
}

答案 2 :(得分:0)

如其他答案中所述,%0..格式字符串修饰符仅适用于数字参数。

对于字符串,您需要手动创建填充并在实际字符串之前添加适当的长度。

%.*s格式字符串修饰符允许您指定字符串的长度。您需要创建一个仅包含0的填充字符串

char test[10] = "abcd";
char padding[25];
memset(padding, '0', sizeof(padding));
printf("%.*s%s", 19-strlen(test), padding , test);

这将产生所需的结果。

您可以看到Demo here

由于您的问题是关于sprintf,因此请说明这与sprintf的工作方式类似。只需创建一个适当大小的缓冲区,它可以容纳填充,实际字符串和空终止符。