RRP
RRP

Reputation: 3

Use sprintf with fixed width, left-justified field and concatenation

I am using sprintf to make nicely columned output (via printf and fprintf) but am having issue with variable string length when combining two strings.

For the most part, I use this and it works:

sprintf(strtmp, "%i\t%-20s\t% 2.2f\t% 2.2f", measnum,
        measurementname, setvalue, measuredvalue);

When run in each measurement function, it outputs like this:

1    MeasurementNameA            75    77 8
2    MeasNameB                   50    52 2

However,sometimes I want to a add to the string but keep it right adjusted. Without fixed width, the code looks like this:

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

1    MeasureNameA    75    77 8  
2    MeasNameB_setup1    50    52 2
3    MeasNameB_setup2    50    51 6

How can I combine these without using multiple steps such that my output is:

1    MeasureNameA                75    77 8
2    MeasNameB_x1                50    52 2
3    MeasNameB_x2                51    53 6

I cannot use boost.

Maybe necessary additional information.
My pseudocode is something like this:

(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

Upvotes: 0

Views: 6615

Answers (5)

Havenard
Havenard

Reputation: 27864

There are some ways you can do this, you can use a temporary buffer to generate the names and then print them:

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);

Or you can explore the wonders of variable padding:

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

Upvotes: 2

Speed8ump
Speed8ump

Reputation: 1317

There's no simple way to do this via only the format specifier. You could use the * specifier in the string format to specify a dynamic string width, but that's still going to require you to calculate the name string length, as well as the added string + number length.

Upvotes: 0

user2371524
user2371524

Reputation:

How can I combine these without using multiple steps [...]

You can't. But you can write a helper function and use that:

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

and then provide a char buf[21] and use it like this:

sprintf(strtmp, "%i\t%s%i\t% 2.2f\t% 2.2f", measnum,
        combineFixedWidth(buf, 20, measurementname, "_setup"),
        counter, setvalue, measuredvalue);

Disclaimer: code typed here, untested, may contain bugs.

Upvotes: 0

NiBZ
NiBZ

Reputation: 532

You could split your sprintf's (and, in the meantime, use snprintf instead, for safety), and use the return value of the previous one to know exactly how much characters have been printed.

Something like that :

// 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);
}

This should work. You can change the split columns by changing the constants, and adjust for thour format. If the inputs are longer than the expected size, then no padding is done.

Upvotes: 0

Jaka Konda
Jaka Konda

Reputation: 1436

You can specify second column width when formating to maximum length of the text it'll hold. If necessary bump up that value.

printf("%-40s", "Some text");

The - left-justifies your text in that field long 40 charcters, otherwise it would be right. There isn't any nice other way to do this. Same applies for sprintf and fprintf.

If you always output to file, you can dump sprintf and directly replace it by fprintf.

Upvotes: 0

Related Questions