c - sintaxis - tabla printf
¿Cuál es el uso del especificador de formato% n en C? (10)
% n es C99, no funciona con VC ++.
¿Cuál es el uso del especificador de formato %n
en C? ¿Alguien podría explicar con un ejemplo?
Almacenará el valor del número de caracteres impresos hasta el momento en esa printf()
.
Ejemplo:
int a;
printf("Hello World %n /n", &a);
printf("Characters printed so far = %d",a);
El resultado de este programa será
Hello World
Characters printed so far = 12
Desde here vemos que almacena la cantidad de caracteres impresos hasta ahora.
n
El argumento debe ser un puntero a un entero en el que se escribe el número de bytes escritos en la salida hasta el momento por esta llamada a una de las funcionesfprintf()
. Ningún argumento se convierte.
Un ejemplo de uso sería:
int n_chars = 0;
printf("Hello, World%n", &n_chars);
n_chars
tendría entonces un valor de 12
.
El argumento asociado con% n se tratará como int * y se rellenará con la cantidad total de caracteres impresos en ese punto de la impresión.
El otro día me encontré en una situación en la que %n
resolvería muy bien mi problema. A diferencia de mi respuesta anterior , en este caso, no puedo idear una buena alternativa.
Tengo un control de GUI que muestra un texto específico. Este control puede mostrar parte de ese texto en negrita (o en cursiva, o subrayado, etc.), y puedo especificar qué parte especificando los índices de caracteres iniciales y finales.
En mi caso, estoy generando el texto para el control con snprintf
, y me gustaría que una de las sustituciones se haga en negrita. Encontrar los índices de inicio y final para esta sustitución no es trivial porque:
La cadena contiene múltiples sustituciones, y una de las sustituciones es texto arbitrario, especificado por el usuario. Esto significa que hacer una búsqueda textual de la sustitución que me importa es potencialmente ambigua.
La cadena de formato podría estar localizada, y podría usar la extensión
$
POSIX para especificadores de formato de posición. Por lo tanto, buscar la cadena de formato original para los especificadores de formato no es trivial.El aspecto de localización también significa que no puedo dividir fácilmente la cadena de formato en varias llamadas a
snprintf
.
Por lo tanto, la manera más directa de encontrar los índices alrededor de una sustitución particular sería hacer:
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);
Hasta ahora, todas las respuestas son sobre eso %n
hace, pero no por qué alguien lo querría en primer lugar. Encuentro que es algo útil con sprintf
/ snprintf
, cuando tal vez necesites dividir o modificar la cadena resultante, ya que el valor almacenado es un índice de matriz en la cadena resultante. Sin embargo, esta aplicación es mucho más útil con sscanf
, especialmente porque las funciones de la familia scanf
no devuelven la cantidad de caracteres procesados sino el número de campos.
Otro uso realmente incorrecto es obtener un pseudo-log10 gratis al mismo tiempo mientras imprime un número como parte de otra operación.
La mayoría de estas respuestas explican qué hace %n
(que es imprimir nada y escribir la cantidad de caracteres impresos hasta el momento en una variable int
), pero hasta ahora nadie ha dado realmente un ejemplo del uso que tiene. Aqui hay uno:
int n;
printf("%s: %nFoo/n", "hello", &n);
printf("%*sBar/n", n, "");
se imprimirá:
hello: Foo
Bar
con Foo y Bar alineados. (Es trivial hacer eso sin usar %n
para este ejemplo en particular, y en general uno siempre podría romper esa primera llamada printf
:
int n = printf("%s: ", "hello");
printf("Foo/n");
printf("%*sBar/n", n, "");
Si la conveniencia ligeramente añadida vale la pena usar algo esotérico como %n
(y posiblemente introducir errores) está abierto al debate.
Nada impreso. El argumento debe ser un puntero a un int firmado, donde se almacena el número de caracteres escritos hasta el momento.
#include <stdio.h>
int main()
{
int val;
printf("blah %n blah/n", &val);
printf("val = %d/n", val);
return 0;
}
El código anterior se imprime:
blah blah
val = 5
No imprime nada. Se usa para averiguar cuántos caracteres se imprimieron antes de que %n
apareciera en la cadena de formato, y se imprimió en la int proporcionada:
#include <stdio.h>
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;
}
Realmente no he visto muchos usos prácticos del especificador %n
el mundo real, pero recuerdo que se usó en vulnerabilidades de printf en la vieja escuela con un ataque de cadena de formato hace bastante tiempo.
Algo que fue como esto
void authorizeUser( char * username, char * password){
...code here setting authorized to false...
printf(username);
if ( authorized ) {
giveControl(username);
}
}
donde un usuario malintencionado podría aprovechar el parámetro de nombre de usuario que pasa a printf como cadena de formato y usar una combinación de %d
, %c
o w / e para pasar por la pila de llamadas y luego modificar la variable autorizada a un valor verdadero.
Sí, es un uso esotérico, pero siempre es útil saber cuándo escribir un daemon para evitar agujeros de seguridad. :RE