¿Cuál es la diferencia entre printf () y pone () en C?

176

Sé que puedes imprimir con printf()y puts(). También puedo ver que le printf()permite interpolar variables y formatear.

Es puts()simplemente una versión primitiva de printf(). ¿Debería usarse para todo lo posible printf()sin interpolación de cadenas?

alex
fuente
47
Solo una nota sobre el uso de printf en lugar de pone: nunca, nunca haga a printf(variable)para imprimir una cadena. Use puts(variable)o printf("%s', variable). Existe un riesgo de seguridad al usar una cadena de formato variable: si un atacante puede escribir la variable, puede atacar el programa usando cadenas de formato.
Zan Lynx

Respuestas:

141

putses más simple que, printfpero tenga en cuenta que el primero agrega automáticamente una nueva línea. Si eso no es lo que quieres, puedes fputsusar la cadena para stdout o usar printf.

Michael Kristofik
fuente
8
Creo que también es importante mencionar los argumentos adicionales que printf toma para agregar variables adicionales a la cadena de salida.
Erutan409
99

(Esto se señala en un comentario de Zan Lynx, pero creo que merece una respuesta, dado que la respuesta aceptada no lo menciona).

La diferencia esencial entre puts(mystr);y printf(mystr);es que en este último el argumento se interpreta como una cadena de formato . El resultado será la misma frecuencia (a excepción de la nueva línea añadida) si la cadena no contiene caracteres de control ( %), pero si no se puede confiar en que (si mystres una variable en lugar de un literal) se debe no usarlo.

Por lo tanto, generalmente es peligroso, y conceptualmente incorrecto , pasar una cadena dinámica como argumento único de printf:

  char * myMessage;
  // ... myMessage gets assigned at runtime, unpredictable content
  printf(myMessage);  // <--- WRONG! (what if myMessage contains a '%' char?) 
  puts(myMessage);    // ok
  printf("%s\n",myMessage); // ok, equivalent to the previous, perhaps less efficient

Lo mismo se aplica a fputsvs fprintf(pero fputsno agrega la nueva línea).

leonbloy
fuente
¿De qué manera el uso printf()sería menos eficiente? ¿En tiempo de ejecución? En tiempo de compilación?
franklin
10
@franklin en tiempo de ejecución, porque printfnecesita analizar la cadena de formato. Sin embargo, esto normalmente debería ser irrelevante. Además, un compilador inteligente podría optimizar esto y reemplazarlo printfcon call toputs
leonbloy el
33

Además del formateo, putsdevuelve un entero no negativo si tiene éxito o EOFno; while printfdevuelve el número de caracteres impresos (sin incluir el nulo final).

Echristopherson
fuente
16

En casos simples, el compilador convierte llamadas printf()a llamadas a puts().

Por ejemplo, el siguiente código se compilará con el código de ensamblaje que muestro a continuación.

#include <stdio.h>
main() {
    printf("Hello world!");
    return 0;
}
push rbp
mov rbp,rsp
mov edi,str.Helloworld!
call dword imp.puts
mov eax,0x0
pop rbp
ret

En este ejemplo, utilicé GCC versión 4.7.2 y compilé la fuente con gcc -o hello hello.c.

Hannu Balk
fuente
9
¿Y qué hay de la nueva línea que pone lugares en stdout?
zubergu
1
Debería haber sido printf("Hello world!\n");gcc, de hecho, eso se traduce en put. Como es un mensaje antiguo, lo editaré yo mismo.
Rafael Almeida
2
¿Cómo leíste el código de ensamblaje después de compilar el código C?
Koray Tugay
3
@KorayTugay: la -save-tempsopción para gcc hace eso
schaiba
También podría usar una herramienta como gdb para desmontar un binario.
Ivan Kaloyanov
10

Bien, printfpodría considerarse como una versión más poderosa de puts. printfproporciona la capacidad de formato de las variables de salida utilizando especificadores de formato, tales como %s, %d, %lf, etc ...

Justin Ethier
fuente
10

En mi experiencia, printf()transporta más código que puts()independientemente de la cadena de formato.

Si no necesito el formato, no lo uso printf. Sin embargo, fwritea stdoutobras mucho más rápido que puts.

static const char my_text[] = "Using fwrite.\n";
fwrite(my_text, 1, sizeof(my_text) - sizeof('\0'), stdout);

Nota: por comentarios, '\ 0' es una constante entera. La expresión correcta debe ser la sizeof(char)indicada por los comentarios.

Thomas Matthews
fuente
2
"fwrite to stdout funciona mucho más rápido que put". - ¿Cuál podría ser la razón?
Antony Hatchkins
66
@AntonyHatchkins Normalmente no es "mucho" más rápido. pone (), sin embargo, tiene que realizar una llamada strlen () cada vez en su cadena, mientras que si se conoce el tamaño con fwrite () se puede evitar. Ese es prácticamente el único contribuyente real a una diferencia de rendimiento.
Wiz
8
Esta respuesta es incorrecta. '\0'tiene tipo int, por lo que en la mayoría de los sistemas se imprimirá Using fwrit. Si desea imprimir 1 byte menos, simplemente use 1. sizeof (char), que es probablemente lo que pretendía aquí, se garantiza que sea 1.
Bradley Garagan
8
int puts(const char *s);

puts () escribe la cadena sy una nueva línea final en stdout.

int printf(const char *format, ...);

La función printf () escribe la salida en stdout, bajo el control de una cadena de formato que especifica cómo se convierten los argumentos posteriores para la salida.

Aprovecharé esta oportunidad para pedirle que lea la documentación.

Koray Tugay
fuente
5

la función printf () se usa para imprimir cadenas y variables en la pantalla, mientras que la función put () solo le permite imprimir una cadena solo en su pantalla.

Wesley Nyandika
fuente
2

putses la opción simple y agrega una nueva línea al final y printfescribe la salida de una cadena formateada.

Consulte la documentación para puts y para printf.

Recomendaría usar solo printfya que esto es más consistente que el método de cambio, es decir, si está depurando, es menos doloroso buscar en todas las impresiones que putsy printf. La mayoría de las veces también desea generar una variable en sus impresiones, por lo que putsse usa principalmente en código de ejemplo.

Johan Engblom
fuente
1

Al comparar puts()y printf(), a pesar de que su consumo de memoria es casi el mismo, puts()lleva más tiempo en comparación printf().

hasta
fuente
Agregue alguna explicación a su respuesta para que otros puedan aprender de ella. ¿Tiene fuentes confiables para esa afirmación? ¿O algunas razones para explicar esta diferencia?
Nico Haase