O que “%. * S” significa em printf?

113

Eu tenho um trecho de código no qual há um

printf("%.*s\n")

o que isso %.*ssignifica?

Shaobo Wang
fonte
26
Sem argumentos adicionais, essa não é uma printfchamada válida .
Andrew Marshall

Respostas:

120

Você pode usar um asterisco ( *) para passar o especificador de largura / precisão para printf(), em vez de codificá-lo na string de formato, ou seja,

void f(const char *str, int str_len)
{
  printf("%.*s\n", str_len, str);
}
AusCBloke
fonte
4
Deve-se notar que o str_lenargumento deve ter tipo int(ou tipo integral mais estreito, que seria promovido a int). Seria um erro para passar long, size_tetc.
MM
10
Vale a pena mencionar que o provável propósito deste código, especialmente quando usado com %s, é imprimir uma sub-string da string original. Nesse caso de uso, strapontaria para algum lugar dentro da string original (possivelmente no início) e str_lenespecificaria o comprimento da substring que deve ser impressa.
Sonic Atom
2
Especificando um comprimento, podemos imprimir (ou sprintf) uma string que não tem terminador nulo, por exemplo, uma string que é inserida de qualquer fluxo ou fonte baseada em arquivo. Que é o caso de uso que encontrei com muito mais frequência do que simplesmente imprimir prettines.
Conrad B
23

Mais detalhado aqui .

valor inteiro ou *que especifica a largura mínima do campo. O resultado é preenchido com caracteres de espaço (por padrão), se necessário, à esquerda quando justificado à direita ou à direita se justificado à esquerda. No caso em que * é usado, a largura é especificada por um argumento adicional do tipo int. Se o valor do argumento for negativo, ele resultará com o sinalizador - especificado e largura de campo positiva. (Observação: esta é a largura mínima: o valor nunca é truncado.)

.seguido por um número inteiro ou *, ou nenhum que especifique a precisão da conversão. No caso em que * é usado, a precisão é especificada por um argumento adicional do tipo int. Se o valor desse argumento for negativo, ele será ignorado. Se nem um número nem * forem usados, a precisão será considerada zero. Veja a tabela abaixo para efeitos exatos de precisão.

Então, se tentarmos as especificações de conversão

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

obtemos a saída:

|Hello wo|
|Hello wo|
|     Hello world|
|     Hello world|
Ondrej
fonte
12

Não acho que o código acima esteja correto, mas (de acordo com esta descrição printf()) os .*meios

A largura não é especificada na string de formato, mas como um argumento de valor inteiro adicional precedendo o argumento que deve ser formatado. '

Portanto, é uma string com uma largura aceitável como argumento.

repetir
fonte
2
Eu adicionei a referência cruzada de URL para que você possa evitar acusações de plágio. Claro, a citação correta diz "A precisão não é ..." em vez de "A largura não é ...".
Jonathan Leffler
Como @MattMcNabb apontou, toda referência a essa página deve destacar que “ um valor inteiro ” é exatamente int(ou um subconjunto dele) - não apenas qualquer valor integral como mais intuitivo size_tou seus possíveis aliases, como std::string::size_type. Isso é ainda mais confuso, levando em consideração que a página referenciada é mencionada size_tcomo um dos especificadores de tipo suportados.
Anton Samsonov