tipos - printf en c
¿Por qué la cadena de formato printf de C tiene% c y% s? (11)
¿Por qué la cadena de formato printf de C tiene %c
y %s
?
Sé que %c
representa un solo carácter y %s
representa una cadena de caracteres terminada en nulo, pero ¿no bastaría solo la representación de cadena?
% c espera una char, que es un valor entero y la imprime de acuerdo con las reglas de codificación.
% s espera un puntero a una ubicación de memoria que contiene valores de char , e imprime los caracteres en esa ubicación de acuerdo con las reglas de codificación hasta que encuentra un carácter 0 (nulo).
Como puede ver, bajo el capó, los dos casos, aunque se parecen, no tienen mucho en común, ya que uno trabaja con valores y el otro con punteros. Una es instrucciones para interpretar un valor entero específico como un carácter ascii, y la otra itera los contenidos de una ubicación de memoria char por char e interpreta hasta que se encuentre un valor cero.
C tiene los especificadores de formato %c
y %s
porque manejan diferentes tipos.
Un char
y una cuerda son tan diferentes como la noche y 1.
Dado que nadie ha proporcionado una respuesta con CUALQUIER referencia, esta es una especificación de printf de pubs.opengroup.com que es similar a la definición de formato de IBM
%do
El argumento int se convertirá a un char sin signo, y el byte resultante se escribirá.
% s
El argumento debe ser un puntero a una matriz de char. Los bytes de la matriz se escribirán (pero no incluirán) cualquier byte nulo de terminación. Si se especifica la precisión, no se escribirán más bytes. Si la precisión no se especifica o es mayor que el tamaño de la matriz, la aplicación se asegurará de que la matriz contenga un byte nulo.
El problema mencionado por otros de que un solo carácter debería ser cancelado no es real. Esto podría abordarse proporcionando una precisión al formato %.1s
haría el truco.
Lo que es más importante en mi opinión es que para %s
en cualquiera de sus formas, debe proporcionar un puntero a uno o varios caracteres. Eso significaría que no podría imprimir rvalues (expresiones calculadas, devoluciones de funciones, etc.) o variables de registro.
Edit: Estoy realmente enojado por la reacción a esta respuesta, por lo que probablemente borre esto, esto realmente no vale la pena. Parece que la gente reacciona al respecto sin siquiera haber leído la pregunta o saber apreciar la tecnicidad de la pregunta.
Para dejarlo en claro: no digo que prefiera %.1s
sobre %c
. Solo digo que las razones por las cuales %c
no pueden ser reemplazadas por eso son diferentes de las otras que pretenden contar. Estas otras respuestas son técnicamente incorrectas. La terminación nula no es un problema con %s
.
He realizado un experimento con printf("%.1s", &c)
y printf("%c", c)
. Usé el código a continuación para probar, y la utilidad de time
de bash es obtener el tiempo de runing.
#include<stdio.h>
int main(){
char c = ''a'';
int i;
for(i = 0; i < 40000000; i++){
//printf("%.1s", &c); get a result of 4.3s
//printf("%c", c); get a result of 0.67s
}
return 0;
}
El resultado dice que usar %c
es 10 veces más rápido que %.1s
. Entonces, aunque% s puede hacer el trabajo de% c, todavía se necesita% c para el rendimiento.
La función printf es una función variadica, lo que significa que tiene una cantidad variable de argumentos. Los argumentos se empujan en la pila antes de llamar a la función (printf). Para que la función printf use la pila, necesita conocer información sobre lo que está en la pila, la cadena de formato se usa para ese fin.
p.ej
printf( "%c", ch ); tells the function the argument ''ch''
is to be interpreted as a character and sizeof(char)
mientras
printf( "%s", s ); tells the function the argument ''s'' is a pointer
to a null terminated string sizeof(char*)
no es posible dentro de la función printf determinar los contenidos de la pila, por ejemplo, distinguiendo entre ''ch'' y ''s'' porque en C no hay verificación de tipo durante el tiempo de ejecución.
Me gustaría agregar otro punto de perspectiva a esta divertida pregunta.
Realmente esto se reduce a la escritura de datos. He visto respuestas aquí que indican que podría proporcionar un puntero al char, y proporcionar un
"%.1s"
Esto podría ser cierto. Pero la respuesta radica en que el diseñador de C intenta brindar flexibilidad al programador y, de hecho, una forma (aunque pequeña) de reducir la huella de su aplicación.
En ocasiones, un programador puede querer ejecutar una serie de sentencias if-else o un switch-case, donde la necesidad es simplemente generar un carácter basado en el estado. Para esto, la codificación dura de los caracteres podría tomar menos espacio real en la memoria ya que los caracteres individuales son de 8 bits frente al puntero que es de 32 o 64 bits (para computadoras de 64 bits). Un puntero ocupará más espacio en la memoria.
Si desea disminuir el tamaño mediante el uso de caracteres reales frente a los indicadores de caracteres, entonces hay dos maneras en que uno podría pensar hacerlo dentro de los tipos de operadores de impresión. Uno sería desconectarse de .1s, pero ¿cómo se supone que la rutina debe saber con certeza que realmente está proporcionando un tipo de caracteres en lugar de un puntero a un carácter o puntero a una cadena (conjunto de caracteres)? Es por eso que usaron el "% c", ya que es diferente.
Pregunta divertida :-)
Para %s
, necesitamos proporcionar la dirección de la cadena, no su valor.
Para %c
, proporcionamos el valor de los caracteres.
Si usamos el %s
lugar de %c
, ¿cómo proporcionaríamos un ''/0''
después de los caracteres?
Probablemente para distinguir entre cadena terminada nula y un personaje. Si solo tuvieran %s
, entonces cada carácter individual también debe ser nulo terminado.
char c = ''a'';
En el caso anterior, c
debe ser nulo terminado. Esta es mi suposición, sin embargo :)
%s
dice imprimir todos los caracteres hasta que encuentre un nulo (trate la variable como un puntero).
%c
dice imprimir solo un caracter (tratar la variable como un código de caracter)
El uso de %s
para un carácter no funciona porque el personaje se tratará como un puntero, luego intentará imprimir todos los caracteres que siguen a ese lugar en la memoria hasta que encuentre un nulo
Robar de las otras respuestas para explicarlo de una manera diferente.
Si desea imprimir un carácter usando %s
, puede usar lo siguiente para pasarle correctamente una dirección de un char y evitar que escriba basura en la pantalla hasta encontrar un nulo.
char c = ''c'';
printf(''%.1s'', &c);
%s
imprime caracteres hasta que llega a 0
(o ''/0''
, lo mismo).
Si solo tienes un char x;
, imprimiéndolo con printf("%s", &x);
- Tendría que proporcionar la dirección, ya que %s
espera un char*
- arrojaría resultados inesperados, ya que &x + 1
podría no ser 0
.
Por lo tanto, no podría imprimir un solo carácter a menos que fuera terminado en nulo (muy ineficiente).
EDITAR: Como otros han señalado, los dos esperan cosas diferentes en los parámetros variables, uno por puntero y el otro como un solo carácter. Pero esa diferencia es algo clara.