繁体   English   中英

在字符串中填充前导零的字符串在Solaris中有效,但在RHEL中不起作用

[英]Padding with leading zero in string works in Solaris but not in RHEL

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

#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;
}

输出:

Solaris : 0000000000000000a12
RHEL    :                 a12 (left padding with spaces)

如何在两个平台上都取得领先的零?

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

prinf()的POSIX规范说:

0
对于diouxXaAeEfFgG转换说明符,使用前导零(跟随符号或基数的任何表示)来填充该字段宽度,而不是执行空格填充,除非转换无穷大或NaN。 如果同时显示“ 0 ”和“ - ”标志,则忽略“ 0 ”标志。 对于diouxX转换说明符,如果指定了精度,则应忽略“ 0 ”标志。 [CX]⌦如果同时显示“ 0 ”和“ <apostrophe>标志,则将分组字符插入零填充之前。 对于其他转换,行为是不确定的。

(请注意解析该语句的注意。“⌫”的出现表明“其他转换”注释仅适用于0'一起出现。”但是,检查C11标准(ISO / IEC 9899:2011)时,它表示:

0
对于diouxXaAeEfFgG转换,使用前导零(跟随符号或基数的任何表示)来填充到字段宽度而不是执行空格填充,除非转换无穷大或NaN。 如果同时出现0-标志,则忽略0标志。 对于diouxX转换,如果指定了精度,则忽略0标志。 对于其他转换,行为是不确定的。

我认为结束标记'material'在POSIX材料中放错了位置。)

因此,要获得可靠的行为,您必须更具创造力。 第一步是从格式字符串中删除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;
}

输出为:

00000000000000000a12syzygy.sv.example.co00000192.168.234.11900000000000Quasimodo

您可以谨慎创建更精细的格式:

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

struct Field
{
    int width;
    char pad;
};

static struct Field fields[] =
{
    { .width = 12, .pad = '0', },
    { .width = 30, .pad = '@', },
    { .width = 15, .pad = '.', },
    { .width = 25, .pad = '-', },
};
enum { NUM_FIELDS = sizeof(fields) / sizeof(fields[0]) };

static char *data[][4] =
{
    { "a12",     "syzygy.sv.example.com", "192.168.234.119", "Quasimodo"             },
    { "zzx2341", "zulu.za.example.com",   "192.168.23.19",   "Beowulf"               },
    { "reynard", "coffee.br.example.com", "192.168.5.9",     "William the Conqueror" },
    { "peanut",  "koala.au.example.com",  "192.168.93.12",   "Quasimodo"             },
};
enum { NUM_ROWS = sizeof(data) / sizeof(data[0]) };

int main(void)
{
    for (int i = 0; i < NUM_ROWS; i++)
    {
        char   buffer[1024];
        char  *bufptr = buffer;
        size_t buflen = sizeof(buffer);
        for (int j = 0; j < NUM_FIELDS; j++)
        {
            int nbytes = snprintf(bufptr, buflen, "[%*.*s]", fields[j].width,
                                  fields[j].width, data[i][j]);
            if ((size_t)nbytes > buflen)
            {
                fprintf(stderr, "Overlength: %zu required\n",
                        sizeof(buffer) - buflen + nbytes + 1);
                return 1;
            }
            size_t leading_blanks = strspn(bufptr + 1, " ");
            memset(bufptr + 1, fields[j].pad, leading_blanks);
            bufptr += nbytes;
            buflen -= nbytes;
        }
        printf("%s\n", buffer);
    }
    return 0;
}

输出:

[000000000a12][@@@@@@@@@syzygy.sv.example.com][192.168.234.119][----------------Quasimodo]
[00000zzx2341][@@@@@@@@@@@zulu.za.example.com][..192.168.23.19][------------------Beowulf]
[00000reynard][@@@@@@@@@coffee.br.example.com][....192.168.5.9][----William the Conqueror]
[000000peanut][@@@@@@@@@@koala.au.example.com][..192.168.93.12][----------------Quasimodo]

您可以尝试如下操作:

#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;
}

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

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

%.*s格式字符串修饰符使您可以指定字符串的长度。 您需要创建一个填充字符串,其中仅包含0

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

这将产生期望的结果。

您可以在此处查看演示

由于您的问题是关于sprintf ,因此请澄清这也将与sprintf相似。 只需创建一个适当大小的缓冲区即可容纳填充,实际字符串和空终止符。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM