¿Cuál es el uso del especificador de formato %n
en C? ¿Alguien podría explicar con un ejemplo?¿Cuál es el uso del especificador de formato% n en C?
Respuesta
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;
}
Los anteriores impresiones de código:
blah blah
val = 5
Darán +1 si agrega un código de ejemplo. –
Menciona que el argumento debe ser un puntero a un int firmado, luego usó un int sin firmar en su ejemplo (probablemente solo un error tipográfico). – bta
¿Puedes explicar por qué tiene que ser un puntero? –
El argumento asociado con el% n será tratado como un int * y se llena con el número de caracteres en total impresas en ese punto en el printf.
De here vemos que almacena el número de caracteres impresos hasta el momento.
n
El argumento debe ser un puntero a un entero en el que está escrito el número de bytes escritos en la salida hasta el momento por esta llamada a uno de losfprintf()
funciones. Ningún argumento se convierte.
Un ejemplo de uso sería:
int n_chars = 0;
printf("Hello, World%n", &n_chars);
n_chars
entonces tener un valor de 12
.
No imprime nada. Se utiliza para calcular cuántos caracteres se imprimieron antes %n
apareció en la cadena de formato, y la salida que a la int proporcionado:
#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 a muchos usos prácticos del mundo real del especificador %n
, pero recuerdo que se usó en vulnerabilidades printf de la vieja escuela con un format string attack 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 era superada en printf como la cadena de formato y utilizar una combinación de %d
, %c
o w/e ir a través de 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 al escribir un daemon para evitar agujeros de seguridad. : D
La mayoría de estas respuestas explicar lo %n
hace (que es para imprimir nada y escribir el número de caracteres impresos hasta el momento a una variable int
), pero hasta ahora nadie ha dado un ejemplo de lo use tiene.Aquí está uno:
int n;
printf("%s: %nFoo\n", "hello", &n);
printf("%*sBar\n", n, "");
imprimirá:
hello: Foo
Bar
con Foo y Bar alineados. (Es trivial para hacer eso sin usar %n
para este ejemplo en particular, y en general uno siempre podía romper esa primera printf
llamada:
int n = printf("%s: ", "hello");
printf("Foo\n");
printf("%*sBar\n", n, "");
Si la conveniencia ligeramente añadido es digno de usar algo esotérico como %n
(y, posiblemente, la introducción de errores) está abierto al debate.)
¡Oh, esto es una versión basada en caracteres de calcular el tamaño de píxel de la cadena en una fuente determinada! – Arkadiy
Podría explicar por qué se necesitan n & * s. ¿Son ambos punteros? –
@AndrewS '& n' es un puntero (' & 'es el operador de dirección-de); un puntero es necesario porque C es pass-by-value, y sin un puntero, 'printf' no puede modificar el valor de' n'. El uso de '% * s' en la cadena de formato' printf' imprime un especificador '% s' (en este caso, la cadena vacía' "" ') utilizando un * ancho de campo * de' n' caracteres. Una explicación de los principios básicos de 'printf' está básicamente fuera del alcance de esta pregunta (y respuesta); Recomiendo leer la documentación 'printf' o hacer tu propia pregunta en SO. – jamesdlin
Hasta ahora todas las respuestas se refieren a eso %n
, pero no por qué alguien querría en primer lugar. Encuentro que es algo útil con sprintf
/snprintf
, cuando tal vez necesite romper 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 el número de caracteres procesados, sino el número de campos.
Otro uso realmente incorrecto es obtener un pseudo-log10 de forma gratuita al mismo tiempo mientras se imprime un número como parte de otra operación.
+1 para mencionar usos para '% n', aunque me gustaría diferir sobre" todas las respuestas ... ". = P – jamesdlin
Los chicos malos gracias por su uso de printf /% n, sprintf y sscanf;) – jww
@noloader: ¿Cómo es eso? * El uso de * '% n' no tiene ningún peligro de vulnerabilidad para un atacante.La infamia fuera de lugar de '% n' realmente pertenece a la práctica estúpida de pasar una cadena de mensaje en lugar de una cadena de formato como argumento de formato. Esta situación, por supuesto, nunca surge cuando '% n' es realmente parte de una cadena de formato intencional que se utiliza. –
% n es C99, funciona no con VC++.
'% n' existía en C89. No funciona con MSVC porque Microsoft lo deshabilitó de forma predeterminada por cuestiones de seguridad; debe llamar '_set_printf_count_output' primero para habilitarlo. (Consulte la respuesta de Merlyn Morgan-Graham.) – jamesdlin
No, C89 no define esta característica/puerta trasera. Consulte K & R + ANSI-C http://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628 ¿dónde está el URL-tagger para comentarios? – user411313
Simplemente estás equivocado. Está listado claramente en la Tabla B-1 (conversiones 'printf') del Apéndice B de K & R, 2da edición. (Página 244 de mi copia). O consulte la sección 7.9.6.1 (página 134) de la especificación ISO C90. – jamesdlin
Almacenará el valor del número de caracteres impresos hasta el momento en esa función printf()
.
Ejemplo:
int a;
printf("Hello World %n \n", &a);
printf("Characters printed so far = %d",a);
La salida de este programa será
Hello World
Characters printed so far = 12
cuando intento codificarlo, me da: Hello World Characters printed hasta el momento = 36 ,,, ,, ¿por qué 36 ?! Uso un GCC de 32 bits en una máquina de Windows. –
El otro día me encontré en una situación en la %n
podría muy bien resolver mi problema. A diferencia de my earlier answer, en este caso, no puedo idear una buena alternativa.
Tengo un control de GUI que muestra 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 el inicio y fin de los índices de esta sustitución no es trivial, ya que:
La cadena contiene múltiples sustituciones, y una de las sustituciones es un 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 puede estar localizada, y puede 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 al
snprintf
.
lo tanto, la forma más sencilla para encontrar los índices en torno a una sustitución particular habría que 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);
Le daré +1 para el caso de uso. Pero fallará en una auditoría, por lo que probablemente deba idear otra forma de marcar el comienzo y el final del texto en negrita. Parece que tres 'snprintf' mientras se comprueban los valores de retorno funcionarán bien, ya que' snprintf' devuelve la cantidad de caracteres escritos. Tal vez algo como: 'int begin = snprintf (...," blah blah% s% f yada yada ", ...);' y 'int end = snprintf (...,"% s ", ...); 'y luego la cola:' snprintf (..., "blah blah"); '. – jww
@jww El problema con múltiples llamadas 'snprintf' es que las sustituciones pueden reorganizarse en otras configuraciones regionales, por lo que no se pueden dividir así. – jamesdlin
- 1. especificador de formato C
- 2. C "% d" especificador de formato
- 3. ¿Qué significa el especificador de formato% * s?
- 4. % p Especificador de formato en c
- 5. Uso del especificador volátil en C/C++/Java
- 6. ¿Por qué el uso del especificador de formato incorrecto en C bloquea mi programa en Windows 7?
- 7. Especificador de formato de 'long long'
- 8. El especificador de formato% a para printf() en C
- 9. ¿Cuál es el propósito de 'n = n'?
- 10. ¿Cuál es el especificador de formato para int corto sin signo?
- 11. ¿Cuál es la diferencia entre '\ n' o "\ n" en C++?
- 12. ¿Cuál es el comportamiento del especificador de conversión `p` con el puntero` NULL`?
- 13. ¿Cuál es el uso del uso de init() en JavaScript?
- 14. ¿Cuál es el propósito del uso?
- 15. Especificador de formato de flotante a cadena
- 16. ¿hay un especificador de formato múltiple en Python?
- 17. Cuál es la diferencia entre el especificador de acceso protegido y el interno protegido en C#
- 18. ¿Cuál es el uso de la sobrecarga const en C++?
- 19. ¿Cuál es el formato del archivo XML Remap para IKVM?
- 20. ¿Cuál es el formato del archivo de ilustraciones de iTunes?
- 21. cuál es el uso del método recycle() en TypedArray
- 22. ¿Cuál es el uso del operador "&" en SQL SERVER
- 23. ¿Cuál es el formato de cadena del Asp.net SessionID?
- 24. ¿Dónde está el especificador de formato DateTime 'Z'?
- 25. ¿Cuál es el beneficio de \ n y PHP_EOL en PHP?
- 26. ¿Cuál es el uso de las etiquetas en C#?
- 27. ¿Cuál es el uso de "anulación abstracta" en C#?
- 28. ¿Cuál es el uso de #if en C#?
- 29. ¿Cuál es el uso de Deployment.Current.Dispatcher.BeginInvoke (() => {...})?
- 30. ¿Cuál es el uso de Indexers?
Qué ha sido del arte de la lectura del manual fina? – Jens
Creo que la verdadera pregunta es ¿cuál es el ** PUNTO ** de una opción como esta? ¿Por qué alguien querría saber el valor de los números de caracteres impresos y mucho menos escribir ese valor directamente en la memoria? Era como si los desarrolladores se aburrieran y decidieran introducir un error en kernal –