Estoy empezando un proyecto de escribir una versión simplificada de la shell de linux en C. yo no soy en absoluto experto con C ni con Linux que es exactamente la razón por la que decidió que sería una buena idea.

Comenzando con el analizador, ya he tenido algunos problemas.

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

Estoy recibiendo una advertencia con gcc: «la comparación con los literales de cadena de resultados en los no especificados de comportamiento» en las líneas comentó con la ADVERTENCIA: «de AQUÍ» (véase el código de abajo).

Tengo ni idea de por qué esto provoca una advertencia, pero el problema real es que a pesar de que yo estoy comparando un «<» a un «<» es no entrar dentro de la si…

Estoy en busca de una respuesta para el problema que se explica, sin embargo si hay algo que ver en el código que debe de ser mejorado por favor decirlo. Sólo tienes que tomar en cuenta que no estoy que competente, y que este es todavía un trabajo en progreso (o mejor aún, un trabajo en el inicio).

Gracias de antemano.

#include <stdio.h>
#include <unistd.h>
#include <string.h>
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] == "<") //WARNING HERE
if (args[i+1] != NULL)
cmd_info->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;
}
  • Si realmente sólo quieres comprobar de un solo carácter, que puede hacer if (args[i] && args[i][0] == '<').
InformationsquelleAutor nunos | 2010-04-08

7 Comentarios

  1. 82

    Desea utilizar strcmp() == 0 para comparar cadenas en lugar de una simple ==, que se acaba de comparar si los punteros son el mismo (lo que no estarán en este caso).

    args[i] es un puntero a una cadena (un puntero a un array de caracteres terminada en null), como es "&" o "<".

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

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

    • +1 en un par de horas. Perfecto simple respuesta.
    • Un decente compilador podría contar 😉 stackoverflow.com/questions/2603039/…
    • Guardar los Unicornios: +1 para ti. Parece que necesitamos para la instalación de un intercambio. 🙂
    • Sebastian: Mientras que en los consejos de ruido se ven de bonito, gcc hizo perfectamente bien aquí – los números de línea, y sólo hay una comparación en esas líneas.
    • Gracias, +1 para ti. 😛
    • Es trabajar para eliminar los dos punteros antes de comparar?

  2. 6
    if (args[i] == "&")

    Ok, vamos a disect lo que esto hace.

    args es un array de punteros. Así que, aquí está la comparación de args[i] (un puntero) para "&" (también un puntero). Así, la única forma en que esto va a cada ser verdad, si en algún lugar tiene args[i]="&" e incluso entonces, "&" no está garantizada a punto para el mismo lugar en todas partes.

    Creo que lo que realmente están buscando es strcmp para comparar la totalidad de la cadena o el deseo de hacer if (*args[i] == '&') para comparar el primer carácter de la args[i] cadena a la & carácter

  3. 6

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

    • 'a' significa que el valor del carácter a.
    • "a" significa que la dirección de la ubicación de memoria en la cadena de "a" se almacena (que suele estar en la sección de datos de su programa de espacio en la memoria). En ese lugar de la memoria, tendrá dos bytes — el carácter 'a' y el nulo terminador de la cadena.
    • args[i] es un char*, no char.
  4. 5

    No se puede comparar cadenas con == en C. De C, las cadenas son sólo (terminada en cero) de las matrices, por lo que necesita utilizar las funciones de cadena para comparar. Consulte la página man de strcmp() y strncmp().

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

    • Él es la comparación de caracteres, no cadenas.
    • Eso es incorrecto. Dicho esto, usted no puede hacer las comparaciones con =, pero usted puede con ==.
    • args[i] == «>» — ok, está bien, hay dos maneras de arreglar eso. Ya sea que usted la cambie a una cadena comparación con una cadena de func, o un personaje comparación con un personaje…
    • Oh, tienes razón… yo analiza args como arg…
  5. 4
    1. clang tiene ventajas en los informes de errores & recuperación.

      $ 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 opción de línea de comandos analizador para usted.

  6. 3

    Esta una vieja pregunta, pero he tenido que explicar a alguien recientemente y pensé que la grabación de la respuesta en este caso sería útil al menos en la comprensión de cómo funciona.

    Literales de cadena como

    "a"

    o

    "This is a string"

    se insertan en el texto o los datos de los segmentos de su programa.

    Una cadena en C es en realidad un puntero a char, y la cadena se entiende la posterior caracteres en la memoria hasta un NUL char es encontrado. Es decir, C no sabe realmente acerca de las cadenas.

    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 primer byte de la cadena en el texto o segmento de datos del programa.

    Pero si tengo

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

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

    Ejemplos ilustrativos:

    Aunque, como su compilador señala con razón, usted no debe hacer esto, en el siguiente se evalúe a true:

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

    pero los siguientes se evalúe a false

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

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

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

    No debe hacerlo porque no es algo que está garantizado para trabajar. Incluso si usted sabe que tipo es siempre utilizar un literal de cadena.

    Yo lo he probado y funciona. Si hago

    A.type = "Car";

    luego blah1 ejecutado y lo mismo para «Motocicleta». Y usted sería capaz de hacer cosas como

    if( A.type == B.type )

    pero esto es simplemente terrible. Estoy escribiendo sobre ello porque creo que es interesante saber por qué funciona, y ayuda a entender por qué no debe hacerlo.

    Soluciones:

    En su caso, lo que quiero 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}

    La anterior cosa con la cadena fue útil porque se puede imprimir el texto, de modo que usted puede tener una matriz como esta

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

    Y ahora que lo pienso, este es propensa a errores, ya que uno debe tener cuidado de mantener el mismo orden que en los tipos de matriz.

    Por lo tanto sería mejor hacer

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

    Me encontré con este problema que hoy trabajan con los clientes del programa.
    El programa funciona bien en VS6.0 utilizando la siguiente:
    (He cambiado un poco)

    //
    //This is the one include file that every user-written Nextest programs needs.
    //Patcom-generated files will also look for this file.
    //
    #include "stdio.h"
    #define IS_NONE( a_key )   ( ( a_key == "none" || a_key == "N/A" ) ? TRUE : FALSE )
    //
    //Note in my environment we have output() which is printf which adds /n at the end
    //
    main {
    char *psNameNone = "none";
    char *psNameNA   = "N/A";
    char *psNameCAT  = "CAT";
    if (IS_NONE(psNameNone) ) {
    output("psNameNone Matches NONE");
    output("%s psNameNoneAddr 0x%x  \"none\" addr 0x%X",
    psNameNone,psNameNone,
    "none");
    } else {
    output("psNameNone Does Not Match None");
    output("%s psNameNoneAddr 0x%x  \"none\" addr 0x%X",
    psNameNone,psNameNone,
    "none");
    }
    if (IS_NONE(psNameNA) ) {
    output("psNameNA Matches N/A");
    output("%s psNameNA 0x%x  \"N/A\" addr 0x%X",
    psNameNA,psNameNA,
    "N/A");
    } else {
    output("psNameNone Does Not Match N/A");
    output("%s psNameNA 0x%x  \"N/A\" addr 0x%X",
    psNameNA,psNameNA,
    "N/A");
    }
    if (IS_NONE(psNameCAT)) {
    output("psNameNA Matches CAT");
    output("%s psNameNA 0x%x  \"CAT\" addr 0x%X",
    psNameNone,psNameNone,
    "CAT");
    } else {
    output("psNameNA does not match CAT");
    output("%s psNameNA 0x%x  \"CAT\" addr 0x%X",
    psNameNone,psNameNone,
    "CAT");
    }
    }

    Si se construye en VS6.0 con la Base de datos del Programa con Editar y Continuar.
    La compara parece funcionar. Con este valor de CADENA está habilitada la agrupación, y el compilador optimiza toda la CADENA de punteros que apuntan A LA MISMA DIRECCIÓN, por lo que esto puede funcionar. Cualquier cadenas creadas sobre la marcha después de tiempo de compilación se tienen DIFERENTES direcciones para generará un error de comparar.
    Advertencia: comparación con los literales de cadena de resultados en comportamiento no especificado
    Cambiar la configuración a la Base de datos del Programa sólo se va a construir el programa, de modo que es un error.

Dejar respuesta

Please enter your comment!
Please enter your name here