Qual é o uso do especificador de formato% n em C?

Qual é o uso do especificador de formato %n em C? Alguém poderia explicar com um exemplo?

Nada impresso. O argumento deve ser um ponteiro para um int assinado, onde o número de caracteres escritos até o momento é armazenado.

 #include  int main() { int val; printf("blah %n blah\n", &val); printf("val = %d\n", val); return 0; } 

O código anterior imprime:

 blah blah val = 5 

A maioria dessas respostas explica o que %n faz (que é imprimir nada e escrever o número de caracteres impressos até agora para uma variável int ), mas até agora ninguém deu um exemplo do uso que fez. Aqui está um:

 int n; printf("%s: %nFoo\n", "hello", &n); printf("%*sBar\n", n, ""); 

vai imprimir:

 hello: Foo Bar 

com Foo e Bar alinhados. (É trivial fazer isso sem usar %n para este exemplo em particular e, em geral, sempre se pode dividir a primeira chamada printf :

 int n = printf("%s: ", "hello"); printf("Foo\n"); printf("%*sBar\n", n, ""); 

Se a conveniência ligeiramente acrescentada vale a pena usar algo esotérico como %n (e possivelmente introduzindo erros) está aberto para debate.)

A partir daqui , vemos que ele armazena o número de caracteres impressos até o momento.

n O argumento deve ser um ponteiro para um inteiro no qual é gravado o número de bytes gravados na saída até o momento por essa chamada para uma das funções fprintf() . Nenhum argumento é convertido.

Um exemplo de uso seria:

 int n_chars = 0; printf("Hello, World%n", &n_chars); 

n_chars teria então um valor de 12 .

Eu realmente não vi muitos usos práticos do mundo real do especificador %n , mas lembro que ele foi usado em vulnerabilidades do printf da velha escola com um ataque de string de formato há um tempo atrás.

Algo que foi assim

 void authorizeUser( char * username, char * password){ ...code here setting authorized to false... printf(username); if ( authorized ) { giveControl(username); } } 

onde um usuário mal-intencionado pode tirar proveito do parâmetro username ser passado para printf como a string de formato e usar uma combinação de %d , %c ou w / e para percorrer a pilha de chamadas e modificar a variável autorizada para um valor verdadeiro.

Sim, é um uso esotérico, mas é sempre útil saber ao escrever um daemon para evitar falhas de segurança? : D

O argumento associado ao% n será tratado como um int * e preenchido com o número total de caracteres impressos naquele ponto no printf.

Até agora, todas as respostas são sobre o %n , mas não porque alguém iria querer isso em primeiro lugar. Eu acho que é um pouco útil com sprintf / snprintf , quando você pode precisar mais tarde quebrar ou modificar a seqüência resultante, uma vez que o valor armazenado é um índice de matriz na seqüência resultante. Este aplicativo é muito mais útil, no entanto, com sscanf , especialmente porque as funções na família scanf não retornam o número de caracteres processados, mas o número de campos.

Outro uso muito ruim é obter um pseudo-log10 de graça ao mesmo tempo em que imprime um número como parte de outra operação.

Outro dia encontrei-me numa situação em que %n resolveria bem o meu problema. Ao contrário da minha resposta anterior , neste caso, não consigo conceber uma boa alternativa.

Eu tenho um controle GUI que exibe algum texto especificado. Esse controle pode exibir parte desse texto em negrito (ou em itálico ou sublinhado, etc.) e eu posso especificar qual parte especificando índices de caractere inicial e final.

No meu caso, estou gerando o texto para o controle com snprintf , e gostaria que uma das substituições fosse feita em negrito. Encontrar os índices inicial e final para essa substituição não é trivial porque:

  • A cadeia contém várias substituições e uma das substituições é um texto arbitrário especificado pelo usuário. Isso significa que fazer uma pesquisa textual sobre a substituição de que me importo é potencialmente ambíguo.

  • A string de formato pode ser localizada e pode usar a extensão $ POSIX para especificadores de formato posicional. Portanto, pesquisar a string de formato original para os especificadores de formato é não-trivial.

  • O aspecto de localização também significa que não posso dividir facilmente a cadeia de formatos em várias chamadas para o snprintf .

Portanto, a maneira mais direta de encontrar os índices em torno de uma substituição específica seria:

 char buf[256]; int start; int end; snprintf(buf, sizeof buf, "blah blah %s %f yada yada %n%s%n yakety yak", someUserSpecifiedString, someFloat, &start, boldString, &end); control->set_text(buf); control->set_bold(start, end); 

Não imprime nada. Ele é usado para descobrir quantos caracteres foram impressos antes que %n aparecesse na string de formato e gerasse a saída para o int fornecido:

 #include  int main(int argc, char* argv[]) { int resultOfNSpecifier = 0; _set_printf_count_output(1); /* Required in visual studio */ printf("Some format string%n\n", &resultOfNSpecifier); printf("Count of chars before the %%n: %d\n", resultOfNSpecifier); return 0; } 

( Documentação para _set_printf_count_output )

Ele armazenará o valor do número de caracteres impressos até o momento nessa printf() .

Exemplo:

 int a; printf("Hello World %n \n", &a); printf("Characters printed so far = %d",a); 

A saída deste programa será

 Hello World Characters printed so far = 12 

% n é C99, não funciona com o VC ++.