Advertencia: la comparación con los literales de cadena da como resultado un comportamiento no especificado

Estoy iniciando un proyecto para escribir un shell simplificado para Linux en C. No soy del todo competente con C ni con Linux, esa es exactamente la razón por la que decidí que sería una buena idea.

Comenzando con el analizador, ya he encontrado algunos problemas.

El código debería ser sencillo, por eso no incluí ningún comentario.

Recibo una advertencia con gcc: “la comparación con los literales de cadena da como resultado un comportamiento no especificado” en las líneas comentadas con “ADVERTENCIA AQUÍ” (consulte el código a continuación).

No tengo idea de por qué esto causa una advertencia, pero el problema real es que, aunque estoy comparando un “<" con un "<", no puedo ingresar al if …

Estoy buscando una respuesta para el problema explicado, sin embargo, si hay algo que ve en el código que debe mejorarse, dígalo. Solo tenga en cuenta que no soy tan competente y que esto todavía es un trabajo en progreso (o, mejor aún, un trabajo en inicio).

Gracias por adelantado.

#include  #include  #include  typedef enum {false, true} bool; typedef struct { char **arg; char *infile; char *outfile; int background; } Command_Info; int parse_cmd(char *cmd_line, Command_Info *cmd_info) { char *arg; char *args[100]; int i = 0; arg = strtok(cmd_line, " \n"); while (arg != NULL) { args[i] = arg; arg = strtok(NULL, " \n"); i++; } int num_elems = i; cmd_info->infile = NULL; cmd_info->outfile = NULL; cmd_info->background = 0; int iarg = 0; for (i = 0; i < num_elems; i++) { if (args[i] == "&") //WARNING HERE return -1; else if (args[i] == "infile = args[i+1]; else return -1; else if (args[i] == ">") //WARNING HERE if (args[i+1] != NULL) cmd_info->outfile = args[i+1]; else return -1; else cmd_info->arg[iarg++] = args[i]; } cmd_info->arg[iarg] = NULL; return 0; } void print_cmd(Command_Info *cmd_info) { int i; for (i = 0; cmd_info->arg[i] != NULL; i++) printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]); printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]); printf("infile=\"%s\"\n", cmd_info->infile); printf("outfile=\"%s\"\n", cmd_info->outfile); printf("background=\"%d\"\n", cmd_info->background); } int main(int argc, char* argv[]) { char cmd_line[100]; Command_Info cmd_info; printf(">>> "); fgets(cmd_line, 100, stdin); parse_cmd(cmd_line, &cmd_info); print_cmd(&cmd_info); return 0; } 

Desea utilizar strcmp() == 0 para comparar cadenas en lugar de un simple == , que solo comparará si los punteros son los mismos (que en este caso no serán).

args[i] es un puntero a una cadena (un puntero a una matriz de caracteres terminados en nulo), como es "&" o "<" .

La expresión argc[i] == "&" comprueba si los dos punteros son iguales (apuntan a la misma ubicación de memoria).

La expresión strcmp( argc[i], "&") == 0 comprobará si el contenido de las dos cadenas es el mismo.

 if (args[i] == "&") 

Ok, vamos a analizar lo que hace esto.

Args es una matriz de punteros. Entonces, aquí está comparando args[i] (un puntero) a "&" (también un puntero). Bueno, la única forma de que esto sea cierto es que en algún lugar donde tengas args[i]="&" y aún así, "&" no garantice que apunten al mismo lugar en todas partes.

Creo que lo que realmente está buscando es strcmp para comparar la cadena completa o su deseo de hacerlo if (*args[i] == '&') para comparar el primer carácter de la cadena args[i] con el carácter &

Hay una distinción entre 'a' y "a" :

  • 'a' significa el valor del carácter a .
  • "a" significa la dirección de la ubicación de la memoria donde se almacena la cadena "a" (que generalmente estará en la sección de datos del espacio de memoria de su progtwig). En esa ubicación de memoria, tendrá dos bytes: el carácter 'a' y el terminador nulo para la cadena.

No puede comparar cadenas con == en C. Para C, las cadenas son solo arreglos (terminados en cero), por lo que necesita usar funciones de cadena para compararlas. Consulte la página de manual de strcmp () y strncmp () .

Si desea comparar un carácter, necesita compararlo con un carácter, no con una cadena. "a" es la cadena a , que ocupa dos bytes (el byte nulo y el byte de terminación), mientras que el carácter a está representado por 'a' en C.

  1. clang tiene ventajas en el reporte y recuperación de errores.

     $ clang errors.c errors.c:36:21: warning: result of comparison against a string literal is unspecified (use strcmp instead) if (args[i] == "&") //WARNING HERE ^~ ~~~ strcmp( , ) == 0 errors.c:38:26: warning: result of comparison against a string literal is unspecified (use strcmp instead) else if (args[i] == "<") //WARNING HERE ^~ ~~~ strcmp( , ) == 0 errors.c:44:26: warning: result of comparison against a string literal is unspecified (use strcmp instead) else if (args[i] == ">") //WARNING HERE ^~ ~~~ strcmp( , ) == 0 

    Se sugiere reemplazar x == y por strcmp(x,y) == 0 .

  2. gengetopt escribe el analizador de opciones de línea de comandos por usted.

Esta es una vieja pregunta, pero recientemente tuve que explicárselo a alguien y pensé que grabar la respuesta aquí sería útil al menos para comprender cómo funciona C.

Literales de cuerda como

 "a" 

o

 "This is a string" 

Se colocan en los segmentos de texto o datos de su progtwig.

Una cadena en C es en realidad un puntero a un char, y se entiende que la cadena son los caracteres subsiguientes en la memoria hasta que se encuentra un char NUL. Es decir, C no sabe realmente sobre cuerdas.

Así que si tengo

 char *s1 = "This is a string"; 

entonces s1 es un puntero al primer byte de la cadena.

Ahora si tengo

 char *s2 = "This is a string"; 

esto también es un puntero al mismo primer byte de esa cadena en el segmento de texto o datos del progtwig.

Pero si tengo

 char *s3 = malloc( 17 ); strcpy(s3, "This is a string"); 

luego s3 es un puntero a otro lugar en la memoria en el que copio todos los bytes de las otras cadenas.

Ejemplos ilustrativos:

Aunque, como su comstackdor señala correctamente, no debes hacer esto, lo siguiente se evaluará como verdadero:

 s1 == s2 // True: we are comparing two pointers that contain the same address 

pero lo siguiente evaluará a falso

 s1 == s3 // False: Comparing two pointers that don't hold the same address. 

Y aunque podría ser tentador tener algo como esto:

 struct Vehicle{ char *type; // other stuff } if( type == "Car" ) //blah1 else if( type == "Motorcycle ) //blah2 

No debes hacerlo porque no es algo que esté garantizado para trabajar. Incluso si sabe que ese tipo siempre se establecerá utilizando un literal de cadena.

Lo he probado y funciona. Si lo hago

 A.type = "Car"; 

entonces blah1 se ejecuta y de manera similar para “Motocicleta”. Y serias capaz de hacer cosas como

 if( A.type == B.type ) 

pero esto es simplemente terrible Escribo sobre esto porque creo que es interesante saber por qué funciona y ayuda a entender por qué no deberías hacerlo.

Soluciones:

En su caso, lo que quiere hacer es usar strcmp(a,b) == 0 para reemplazar a == b

En el caso de mi ejemplo, debe utilizar una enumeración.

 enum type {CAR = 0, MOTORCYCLE = 1} 

Lo anterior con la cadena fue útil porque podría imprimir el tipo, por lo que podría tener una matriz como esta

 char *types[] = {"Car", "Motorcycle"}; 

Y ahora que lo pienso, esto es propenso a errores, ya que uno debe tener cuidado de mantener el mismo orden en la matriz de tipos.

Por lo tanto, podría ser mejor hacer

 char *getTypeString(int type) { switch(type) case CAR: return "Car"; case MOTORCYCLE: return "Motorcycle" default: return NULL; }