Esto puede sonar como una pregunta de entrevista, pero en realidad es un problema práctico.
Estoy trabajando con una plataforma integrada y solo tengo disponibles los equivalentes de esas funciones:
imprimirf()
snprintf()
Además, el printf() Es probable que la implementación (y la firma) cambien en un futuro cercano, por lo que las llamadas deben residir en un módulo separado para que sea fácil de migrar más adelante.
Dado eso, ¿puedo envolver las llamadas de registro en alguna función o macro? El objetivo es que mi código fuente llame THAT_MACRO("Number of bunnies: %d", numBunnies); en mil lugares, pero las llamadas a las funciones anteriores se ven solo en un solo lugar.
Compilador: arm-gcc -std=c99
Editar: solo por mencionar, pero las mejores prácticas posteriores a 2000 y probablemente mucho antes, las funciones en línea son mucho mejores que las macros por numerosas razones.
¿Su compilador admite macros variadas?
– alk
17 dic 2013 a las 16:37
¿Qué restricciones del compilador existen? Si esto debe ejecutarse en una versión de C anterior a C99, será difícil lograrlo de forma portátil como una macro.
– ldav1s
17 dic 2013 a las 16:37
@KerrekSB Pensé ¿POR QUÉ? ¿Se bloquearon los comentarios en estos días?
también hay vsnprintf, vfprintf y lo que se te ocurra en stdio.
Además, puede encontrar documentación sobre macros (y macros variables) aquí.
– jmlemetayer
17 de diciembre de 2013 a las 16:41
@Roddy Sí, si desea reenviar todos los argumentos. Lo desaconsejaría ya que no puede definir una macro sin operaciones de esa manera. Con una macro similar a una función, siempre puede hacer que no funcione si es necesario.
– sergey l.
17 de diciembre de 2013 a las 16:42
Desearía que alguien editara esta respuesta para poder eliminar mi voto a favor. NO tengo vprintf u otras fantasías. Embebido, ya sabes.
– Vorác
18 de diciembre de 2013 a las 12:37
Lo siento por el tono. Realmente no puedo usar las bibliotecas estándar para esto. Es una plataforma personalizada basada en ARM.
– Vorác
18 de diciembre de 2013 a las 13:33
He estado probando varios métodos como este, pero 1. No puedo hacer macros que funcionen a través de espacios de nombres; #define Log::WriteLine(_Format, ...) printf(_Format, __VA_ARGS__) no funciona Y 2. No muestra el %s etc. en verde lima, o validar la entrada… y por lo tanto es inútil como sustituto. Si hay alguna forma de obtener un printf personalizado que muestre el %s etc. en verde lima, con la validación que es imprescindible para su uso?
como no dijiste que tienes vprintf o algo asi Si tiene algo así, podría envolverlo en una función como la que Sergey L ha proporcionado en su respuesta.
El TM_PRINTF anterior no funciona con una lista VA_ARGS vacía. Al menos en GCC es posible escribir:
Los dos signos ## eliminan el exceso de coma delante de ellos si __VA_ARGS__ esta vacio.
TM_PRINTF("Starting ei-oh!"); rendimientos error: expected expression before ')' token. Sin el argumento de cadena de formato, funciona. ¿Los argumentos variádicos deben ser distintos de cero en número?
Puede resolver el problema eliminando la parte _f y manteniendo solo la cosa varidac. Funciona sin problemas para mí, pero no sé si está fuera de estándar.
– Lesto
30 de septiembre de 2016 a las 10:12
@lesto, sí, “funciona”, pero eliminando f_ haría TM_PRINTF() admisible. Si esa cadena estuviera en el código, el compilador se quejaría más tarde sobre printf() que no coincide con su firma de función. Es mejor hacer que el compilador se queje TM_PRINTF en este caso, ya que eso es más visible.
– ldav1s
30 de septiembre de 2016 a las 14:39
@ ldav1s No entendí lo que querías decir con una macro “variádica”. Como por arte de magia esos puntos suspensivos ... reenviarlos a __VA_ARGS__ ?
– John Strod
29/10/2016 a las 17:04
Si puedes vivir con tener que envolver la llamada dos paréntesis, puedes hacerlo así:
#define THAT_MACRO(pargs) printf pargs
Entonces úsalo:
THAT_MACRO(("This is a string: %s\n", "foo"));
^
|
OMG
Esto funciona ya que, desde el punto de vista del preprocesador, la lista completa de argumentos se convierte en un macroargumento, que se sustituye por el paréntesis.
Esto es mejor que simplemente hacer
#define THAT_MACRO printf
Ya que te permite definirlo:
#define THAT_MACRO(pargs) /* nothing */
Esto “comerá” los argumentos de la macro, nunca serán parte del código compilado.
ACTUALIZAR Por supuesto, en C99 esta técnica es obsoleta, solo use una macro variádica y sea feliz.
Dios mío, gracias por la gran respuesta. Supongo que recibirás votos a favor de todos los pobres programadores de C89 durante los próximos años 🙂
– Vorác
18 de diciembre de 2013 a las 12:51
Un efecto secundario importante de esta técnica: todas las llamadas a THAT_MACRO necesitará paréntesis dobles, incluso con llamadas de un solo argumento, por ejemplo THAT_MACRO(("Foo Bar")). –Con amor, un pobre programador de C89 de varios años después.
Define la macro parametrizada PRINTF para aceptar (hasta) argumentos infinitos, luego la preprocesa desde PRINTF(...) para printf(__VA_ARGS__). __VA_ARGS__ se usa en definiciones de macros parametrizadas para denotar los argumentos dados (porque no puedes nombrar argumentos infinitos, ¿verdad?).
Comunidad
¿Biblioteca limitada? ¿Sistema Integrado? ¿Necesita el mayor rendimiento posible? ¡No hay problema!
Como se demuestra en esta respuesta a esta pregunta, puede usar el lenguaje ensamblador para envolver funciones que no aceptan VA_LIST en las que sí lo hacen, ¡implementando su propio vprintf a bajo costo!
Si bien esto funcionará, y es casi seguro que dará como resultado el rendimiento y la abstracción que desea, solo recomendaría que obtenga una biblioteca estándar con más funciones, tal vez cortando partes de uClibc. Tal solución seguramente será una respuesta más portátil y, en general, más útil que usar el ensamblaje, a menos que necesite absolutamente todos los ciclos.
Es por eso que tales proyectos existen, después de todo.
Behzad
Esta es una versión ligeramente modificada de la excelente respuesta de @ ldav1 que imprime el tiempo antes del registro:
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información
¿Su compilador admite macros variadas?
– alk
17 dic 2013 a las 16:37
¿Qué restricciones del compilador existen? Si esto debe ejecutarse en una versión de C anterior a C99, será difícil lograrlo de forma portátil como una macro.
– ldav1s
17 dic 2013 a las 16:37
@KerrekSB Pensé ¿POR QUÉ? ¿Se bloquearon los comentarios en estos días?
– Roddy
17 de diciembre de 2013 a las 16:41