¿Qué significa "%. * S" en printf?

112

Tengo un fragmento de código en el que hay un

printf("%.*s\n")

que %.*ssignifica

Shaobo Wang
fuente
26
Sin argumentos adicionales, esa no es una printfllamada válida .
Andrew Marshall

Respuestas:

119

Puede usar un asterisco ( *) para pasar el especificador de ancho / precisión printf(), en lugar de codificarlo en la cadena de formato, es decir

void f(const char *str, int str_len)
{
  printf("%.*s\n", str_len, str);
}
AusCBloke
fuente
3
Cabe señalar que el str_lenargumento debe tener tipo int(o tipo integral más estrecho, al que se promovería int). Sería un error pasar long, size_t, etc.
MM
9
Vale la pena mencionar que el propósito probable de este código, especialmente cuando se usa con %s, es imprimir una subcadena de la cadena original. En este caso de uso, strapuntaría a algún lugar dentro de la cadena original (posiblemente al principio) y str_lenespecificará la longitud de la subcadena que se debe imprimir.
Sonic Atom
2
Al especificar una longitud, podemos evitar la impresión (o sprintf) de una cadena que no tiene terminador nulo, por ejemplo, una cadena que se ingresa desde cualquier fuente basada en flujo o archivo. Que es mucho más a menudo el caso de uso que he encontrado, que simplemente imprimir bonitos.
Conrad B
23

Más detallado aquí .

valor entero o *que especifica el ancho mínimo del campo. El resultado se rellena con espacios (de forma predeterminada), si es necesario, a la izquierda cuando se justifica a la derecha, oa la derecha si se justifica a la izquierda. En el caso de que se utilice *, el ancho se especifica mediante un argumento adicional de tipo int. Si el valor del argumento es negativo, resulta con el indicador - especificado y un ancho de campo positivo. (Nota: este es el ancho mínimo: el valor nunca se trunca).

.seguido de un número entero o *, o ninguno que especifique la precisión de la conversión. En el caso de que se utilice *, la precisión se especifica mediante un argumento adicional de tipo int. Si el valor de este argumento es negativo, se ignora. Si no se utiliza un número ni *, la precisión se toma como cero. Consulte la tabla siguiente para conocer los efectos exactos de la precisión.

Entonces, si probamos ambas especificaciones de conversión

#include <stdio.h>

int main() {
    int precision = 8;
    int biggerPrecision = 16;
    const char *greetings = "Hello world";

    printf("|%.8s|\n", greetings);
    printf("|%.*s|\n", precision , greetings);
    printf("|%16s|\n", greetings);
    printf("|%*s|\n", biggerPrecision , greetings);

    return 0;
}

obtenemos la salida:

|Hello wo|
|Hello wo|
|     Hello world|
|     Hello world|
Ondrej
fuente
12

No creo que el código anterior sea correcto, pero (de acuerdo con esta descripción de printf()) los .*medios

El ancho no se especifica en la cadena de formato, sino como un argumento de valor entero adicional que precede al argumento que tiene que formatearse. '

Entonces es una cadena con un ancho aceptable como argumento.

repetición
fuente
2
Agregué la referencia cruzada de URL para que pueda evitar cargos de plagio. Por supuesto, la cita correcta dice "La precisión no es ..." en lugar de "El ancho no es ...".
Jonathan Leffler
Como señaló @MattMcNabb, cada referencia a esa página debe resaltar que “ un valor entero ” es exactamente int(o un subconjunto de él), no cualquier valor integral como más intuitivo size_to sus posibles alias, como std::string::size_type. Esto es aún más confuso, teniendo en cuenta que la página a la que se hace referencia se menciona size_tcomo uno de los especificadores de tipo admitidos.
Anton Samsonov