Quiero depurar mi programa de microcontrolador en C enviando cadenas a través de UART. Ahora tengo un problema al unir cadenas de depuración, ya que tengo que trabajar con cadenas c. Necesito tener debugMessageOnStack en la pila.
Considere el siguiente ejemplo: necesito una cadena como "Mi color favorito es el rosa mountbatten"
const char debugMessageStart[] = "My favorite color is "; const char* colors[MAX_COLORS] = {[GREEN] = "green", [ORANGE] = "orange", [PINK] = "mountbatten pink"}; char debugMessageOnStack[DEBUG_MESSAGE_LENGTH]; Sé que es bastante fácil calcular DEBUG_MESSAGE_LENGTH a mano, pero quiero que se calcule de forma dinámica, por lo que no tengo que volver a calcularlo a mano cada vez que agrego una nueva cadena de color que es más larga que todas las cadenas de color existentes.
Teóricamente, debería ser posible ya que cada longitud de cadena en colors se conoce antes de compilar, pero no sé cómo puedo hacerlo.
¡Gracias!
En primer lugar, "pero quiero que se calcule dinámicamente" no tiene mucho sentido ya que su matriz debe ser lo suficientemente grande como para manejar el peor de los casos. Su código no puede correr hacia el bosque con un desbordamiento de pila durante el peor de los casos, por lo que simplemente podría asignar la matriz lo suficientemente grande para eso.
No tiene sentido "ahorrar algo de espacio en la pila" cuando no está en el peor de los casos, ya que de todos modos es solo una variable local y se desasignará después de su uso sin importar el tamaño.
En lugar de una matriz de cadenas, use una matriz de estructuras:
typedef struct { size_t length; const char* str; } color_t; const color_t colors[] = { [GREEN] = { sizeof("green")-1, "green" }, ... };De esa manera, todo se almacena en flash y se calcula en tiempo de compilación. Si es pedante acerca de reducir la repetición de código, entonces podría agregar una macro misteriosa (generalmente no recomendada):
#define COLOR_INIT(str) { sizeof(str)-1, str } ... [GREEN] = COLOR_INIT("green"),En general, se debe evitar usar un objeto de tamaño variable en la pila. En primer lugar, existe el riesgo de que el tamaño de la cadena crezca demasiado como para mantenerse en la pila. La segunda asignación de pila con VLA automáticos o alloca() suele ser menos eficiente que para un objeto de tamaño fijo (aunque aún más rápido que malloc() ).
De todos modos, para lidiar con una cadena de tamaño desconocido en la pila, puede usar la función snprintf . La función funciona como printf() pero almacena los caracteres en una cadena. Sin embargo, si uno pasa NULL como búfer y 0 como tamaño, devuelve una cantidad de caracteres que se almacenarían en un búfer.
La cadena se produciría en dos pasadas:
size_t n = snprintf(NULL, 0, "My favorite color is %s", colors[ORANGE]); char msg[n + 1]; // 1 for the terminator snprintf(msg, n + 1, "My favorite color is %s", colors[ORANGE]);Puede ser una buena idea envolver la generación de mensajes en un asistente para evitar repetir:
size_t mk_msg(char *msg, size_t n, int color) { return snprintf(msg, n, "My favorite color is %s", colors[color]); }La ventaja de esta metodología es que es muy genérica y reutilizable.
Si su compilador admite VLA, puede usar esto:
#include <stdio.h> #include <string.h> #define MAX_COLORS 3 #define GREEN 0 #define ORANGE 1 #define PINK 2 const char debugMessageStart[] = "My favorite color is "; const char* colors[] = { [GREEN] = "green",[ORANGE] = "orange", [PINK] = "mountbatten pink" }; int main(void) { const char* color = colors[ORANGE]; int length = strlen(debugMessageStart) + strlen(color) + 1; char debugMessageOnStack[length]; strcpy(debugMessageOnStack, debugMessageStart); strcat(debugMessageOnStack, color); printf("%s\n", debugMessageOnStack); }