Linux: print zero line of specified length

On Linux I am using GNU gcc version 4.9.2 and am getting strange unexpected behavior when trying to print a null string of the specified length. Here is the piece of code I'm trying to do:

#include <cstdio>
#include <cstring>
int main()
{
  char buff[5];
  sprintf(buff,"%04s","12");
  printf("%s\n", buff);
  return 0;
}

      

Whereas the documentation provided at http://www.cplusplus.com/reference/cstdio/printf/ clearly states that the flag aligns the number with zeros (0) instead of spaces when padded. But it printed the space "12", that is, "12", not "0012". fix?

+3


source to share


2 answers


C11 7.21.6.1p6 clearly states that the behavior 0

when combined with s

the conversion specifier is undefined

0

For d

, i

, o

, u

, x

, x

, a

, a

, e

, e

, f

, f

, g

and g

, leading zeros (after any sign or indication base) used to fill the width of the field instead of performing space, except when transformed infinity or NaN. If flags 0

and appear -

, the flag is 0

ignored. For transformation d

, i

, o

, u

, x

, x

, if specified accuracy, the flag 0

is ignored. For other conversions, the behavior is undefined.

So the behavior %04s

is undefined and you're in luck when it didn't live up to your expectations right away!


So here's the complete library to make the left pane work efficiently:



char *leftpad(char *str, size_t length, char fill, char buf[]) {
    size_t s_len = strlen(str);
    if (s_len > length) {
        return NULL;
    }

    size_t padding = length - s_len;
    memset(buf, fill, padding);
    strcpy(buf + padding, str);
    return buf;
}

      

This will also work neatly with any padding character and any padding length. Usage example:

int main(void) {
    char buf[65], *s;
    if (s = leftpad(buf, 64, '0', "12")) {
        puts(s);
    }
}

      

Naturally, this does not work if the string, for example, is a negative decimal string (filling must be up to the sign).

+3


source


In the manpage of printf you will find an exact description:

0

The value must be zero. For d

, i

, o

, u

, x

, x

, a

, a

, e

, e

, f

, f

, g

and g

, the converted value is filled to the left with zeros rather than blanks. [...] For other conversions, the behavior is undefined.

Hence it is not defined for strings. The implementation can contain 0, but is not required. This behavior is undefined.

The following solution uses syntax %.*s

as a format specifier, so there is no need to use a for loop or multiple printf calls.

char buff[5];
char str[] = "12";
size_t len = strlen(str);
sprintf(buff, "%.*s%s", len >= 4 ? 0 : (int)(4 - len), "0000", str);

      




Next, you should consider using snprintf

it to prevent a buffer overflow.

snprintf(buff, sizeof(buff), "%.*s%s", len >= 4 ? 0 : (int)(4 - len), "0000", str);

      

The formatted output from snprintf

may differ from compiler to compiler. On Linux gcc is always appended with a trailing null byte '\0'

. The Visual Studio 2010 compiler does not guarantee that if the string to write is greater than or equal to the buffer.

+5


source







All Articles