C++ 使用具有固定宽度、左对齐字段和连接的sprintf

C++ 使用具有固定宽度、左对齐字段和连接的sprintf,c++,c,printf,C++,C,Printf,我正在使用sprintf来生成精确的列输出(通过printf和fprintf),但是在组合两个字符串时,我遇到了可变字符串长度的问题 在大多数情况下,我使用它,它可以工作: sprintf(strtmp, "%i\t%-20s\t% 2.2f\t% 2.2f", measnum, measurementname, setvalue, measuredvalue); 在每个测量功能中运行时,其输出如下: 1 MeasurementNameA 75

我正在使用
sprintf
来生成精确的列输出(通过
printf
fprintf
),但是在组合两个字符串时,我遇到了可变字符串长度的问题

在大多数情况下,我使用它,它可以工作:

sprintf(strtmp, "%i\t%-20s\t% 2.2f\t% 2.2f", measnum,
        measurementname, setvalue, measuredvalue);
在每个测量功能中运行时,其输出如下:

1    MeasurementNameA            75    77 8
2    MeasNameB                   50    52 2
sprintf(strtmp, "%i\t%s_setup%i\t% 2.2f\t% 2.2f", measnum,
        measurementname, counter, setvalue, measuredvalue);
(measurementA)
   -Setup measurement A -
   -Take measurement A -
   -sprintf
   -printf, fprintf

(measB)
   -Setup measurement B
   for(x=1; x<10; x++)
       -Set x
       -Take measurement B
          -sprintf
          -printf, fprintf
          -end for loop
sprintf(strtmp, "%i\t%s%i\t% 2.2f\t% 2.2f", measnum,
        combineFixedWidth(buf, 20, measurementname, "_setup"),
        counter, setvalue, measuredvalue);
但是,有时我想添加一个字符串,但要保持正确的调整。如果没有固定宽度,代码如下所示:

1    MeasurementNameA            75    77 8
2    MeasNameB                   50    52 2
sprintf(strtmp, "%i\t%s_setup%i\t% 2.2f\t% 2.2f", measnum,
        measurementname, counter, setvalue, measuredvalue);
(measurementA)
   -Setup measurement A -
   -Take measurement A -
   -sprintf
   -printf, fprintf

(measB)
   -Setup measurement B
   for(x=1; x<10; x++)
       -Set x
       -Take measurement B
          -sprintf
          -printf, fprintf
          -end for loop
sprintf(strtmp, "%i\t%s%i\t% 2.2f\t% 2.2f", measnum,
        combineFixedWidth(buf, 20, measurementname, "_setup"),
        counter, setvalue, measuredvalue);

如何在不使用多个步骤的情况下组合这些步骤,从而使我的输出为:

1    MeasureNameA                75    77 8
2    MeasNameB_x1                50    52 2
3    MeasNameB_x2                51    53 6
我不能用boost

可能需要更多信息。
我的伪代码是这样的:

1    MeasurementNameA            75    77 8
2    MeasNameB                   50    52 2
sprintf(strtmp, "%i\t%s_setup%i\t% 2.2f\t% 2.2f", measnum,
        measurementname, counter, setvalue, measuredvalue);
(measurementA)
   -Setup measurement A -
   -Take measurement A -
   -sprintf
   -printf, fprintf

(measB)
   -Setup measurement B
   for(x=1; x<10; x++)
       -Set x
       -Take measurement B
          -sprintf
          -printf, fprintf
          -end for loop
sprintf(strtmp, "%i\t%s%i\t% 2.2f\t% 2.2f", measnum,
        combineFixedWidth(buf, 20, measurementname, "_setup"),
        counter, setvalue, measuredvalue);
(测量数据)
-设置测量A-
-测量-
-斯普林特
-printf,fprintf
(measB)
-设置测量B

对于(x=1;x您可以在格式化为它将容纳的文本的最大长度时指定第二列宽度。如有必要,可以增大该值

printf("%-40s", "Some text");
-
左对齐字段中的文本长度为40个字符,否则它将是右对齐的。没有其他方法可以做到这一点。 这同样适用于
sprintf
fprintf

如果总是输出到文件,则可以转储
sprintf
,并直接将其替换为
fprintf

如何在不使用多个步骤的情况下组合这些内容[…]

您不能。但是您可以编写一个助手函数并使用它:

const char *combineFixedWidth(char *buf, size_t width, const char *str, const char *suff)
{
    size_t len, slen;

    memset(buf, ' ', width);
    buf[width] = 0;
    len = strlen(str);
    slen = strlen(suff);
    if (len > width)
    {
        memcpy(buf, str, width);
        return buf;
    }
    memcpy(buf, str, len);
    width -= len;
    if (slen < width) width = slen;
    memcpy(buf+len, suff, width);
    return buf;
}

免责声明:此处键入的未经测试的代码可能包含错误。

您可以拆分您的
sprintf
(同时,为了安全起见,请使用
snprintf
),并使用前一个的返回值来准确知道打印了多少字符

诸如此类:

// Will split in columns = 10, 50, 60
void formatMyString(int num, char *name, int counter, float setval, float mes)
{
    char buf[256] = {0};
    int cnt = 0;
    cnt = snprintf(buf, 256-cnt, "%i ", num);
    if (cnt < 10) {
        memset(&buf[cnt], ' ', 10-cnt);
        cnt = 10;
    }
    cnt += snprintf(&buf[cnt], 256-cnt, "%s_setup%i ", name, counter);
    if (cnt < 50) {
        memset(&buf[cnt], ' ', 50-cnt);
        cnt = 50;
    }
    cnt += snprintf(&buf[cnt], 256-cnt, "%2.2f ", setval);
    if (cnt < 60) {
        memset(&buf[cnt], ' ', 60-cnt);
        cnt = 60;
    }
    snprintf(&buf[cnt], 256-cnt, "%2.2f", mes);
    printf("%s\n", buf);
}
//将拆分为10、50、60列
void formatMyString(int num,char*name,int计数器,float setval,float mes)
{
char buf[256]={0};
int-cnt=0;
cnt=snprintf(buf,256 cnt,“%i”,num);
if(cnt<10){
memset(&buf[cnt],'',10 cnt);
cnt=10;
}
cnt+=snprintf(&buf[cnt],256 cnt,“%s_设置%i”,名称,计数器);
如果(碳纳米管<50){
memset(&buf[cnt],'',50 cnt);
cnt=50;
}
cnt+=snprintf(&buf[cnt],256 cnt,“%2.2f”,setval);
如果(碳纳米管<60){
memset(&buf[cnt],'',60 cnt);
cnt=60;
}
snprintf(&buf[cnt],256 cnt,“%2.2f”,mes);
printf(“%s\n”,buf);
}
这应该行得通。您可以通过更改常量来更改拆分列,并根据您的格式进行调整。
如果输入长度超过预期大小,则不进行填充。

仅通过格式说明符没有简单的方法。您可以在字符串格式中使用*说明符指定动态字符串宽度,但这仍然需要您计算名称字符串长度以及添加的字符串+数字长度.

有一些方法可以做到这一点,您可以使用临时缓冲区生成名称,然后打印它们:

char buf[64];
snprintf(buf, 64, "%s_setup%i", measurementname, counter);
sprintf(strtmp, "%i\t%-20s\t% 2.2f\t% 2.2f", measnum, buf, setvalue, measuredvalue);
或者,您也可以探索可变填充的奇妙之处:

sprintf(strtmp, "%i\t%s_setup%*i\t% 2.2f\t% 2.2f", measnum,
    measurementname, strlen(measurementname) - 14, counter, setvalue, measuredvalue);

为什么只显示伪代码?在
1measurementnamea75778
中,在
MeasurementNameA
之后有3个数字。
8
来自哪里?Cleb-因为我简化了一组较大的代码,以排除我无法共享的内容,并且只包含相关信息,即格式化字符串s、
Alk-在我的格式化字符串或stackoverflow输入中
Chux-应该是一个十进制77点8。这并不能回答问题,请再次查看发布的代码。这里使用此技术的更多信息:这并不能解决需要在-40宽度中放入2个fiel的问题。