Tokens, identificadores y literales: la base de C

Cuando el compilador procesa tu archivo fuente, no entiende la lógica de inmediato. Primero, debe realizar el análisis léxico, un proceso que descompone el texto en unidades mínimas de significado llamadas tokens. Un token puede ser una palabra clave (como int o return), un identificador (el nombre que tú le das a una variable), un literal (un valor constante como 42), un operador (+, *) o un símbolo de puntuación (;, {). Entender esta estructura es fundamental porque es la base sobre la que se construye toda la sintaxis de C; si no respetas las reglas de formación de estos tokens, el compilador no podrá interpretar tus instrucciones. Esto es algo que aplicarás en cada línea de código que escribas. Si fallas en esto, ya sea por usar un carácter ilegal o por usar un nombre reservado por el compilador, el proceso de compilación fallará con errores de sintaxis que, si no comprendes su origen, te costará mucho depurar.

Los identificadores son los nombres que asignas a variables, funciones o tipos de datos. Para que sean válidos, deben seguir estas reglas: pueden contener letras (mayúsculas o minúsculas), dígitos y el guion bajo (_), pero nunca pueden empezar con un dígito. Un detalle crucial de la arquitectura de C es que los identificadores que comienzan con un guion bajo seguido de una mayúscula (_Nombre) o aquellos que contienen dos guiones bajos consecutivos (__nombre) están reservados para la implementación; esto significa que el compilador o las librerías estándar de tu sistema podrían usarlos para sus propios fines. Si usas uno por accidente, podrías causar conflictos impredecibles en el enlace del programa.

Los literales son valores constantes que se representan directamente en el código. Existen varios tipos:
* Enteros: Se pueden escribir en base decimal (10), octal si empiezan con 0 (012) [C89], hexadecimal si empiezan con 0x (0x1A) o binario si usas el prefijo 0b [C23]. Para definir la precisión, usamos sufijos: u o U para unsigned, l o L para long, y ll o LL para long long. Una mejora reciente en C23 es el uso del separador de dígitos ' (ej. 1_000_000) para mejorar la legibilidad sin cambiar el valor.
* Punto flotante: Representan números con decimales. Además de la notación decimal (3.14), C99 introdujo la notación hexadecimal para representar valores de punto flotante de forma exacta (0x1.p-3).
* Caracteres: Se escriben entre comillas simples ('a'). Pueden ser caracteres estándar, secuencias de escape como el salto de línea ('\n') o valores representados en octal ('\101') o hexadecimal ('\x41').
* Strings: Se escriben entre comillas dobles ("Hola"). Un detalle interesante es la concatenación de literales: si pones dos strings uno junto al otro, el compilador los une en uno solo durante el tiempo de compilación.

Los comentarios sirven para documentar el código y son ignorados por el compilador. Los comentarios multilínea /* ... */ son parte del estándar desde C89, mientras que los comentarios de una sola línea // se introdujeron en C99.

#include <stdio.h>

int main(void) {
    /* Comentario multilínea [C89] 
       que abarca varias líneas */
    int comentario_en_linea = 10; // Comentario de una línea [C99]

    // Identificadores válidos
    int variable_valida = 100;
    int _variable_con_guion = 20;

    // Literales enteros
    int decimal = 255;
    int octal = 0377;           // Representa 255 en octal
    int hexadecimal = 0xFF;     // Representa 255 en hexadecimal
    int binario = 0b11111111;   // Representa 255 en binario [C23]
    unsigned long long grande = 1_000_000_000ULL; // C23 y sufijo

    // Literales de punto flotante
    float pi = 3.14159f;
    double d_precision = 3.1415926535;
    double hex_float = 0x1.p3;  // 1.0 * 2^3 = 8.0 [C99]

    // Literales de carácter
    char letra = 'A';
    char salto = '\n';
    char hex_char = '\x41';     // 'A' en hexadecimal
    char oct_char = '\101';     // 'A' en octal

    // Literales de string y concatenación
    const char *mensaje = "Hola, " "Mundo"; // Se une en "Hola, Mundo"

    // Mostrar resultados para verificar
    printf("Hex: 0x%X, Octal: %o, Binario: %b\n", hexadecimal, octal, binario);
    printf("%s\n", mensaje);
    printf("Char hex: %c\n", hex_char);
    printf("Valor grande: %llu\n", grande);

    return 0;
}

Análisis del ejemplo

En el código anterior, fíjate en cómo variable_valida y _variable_con_guion cumplen las reglas de los identificadores. Sin embargo, nota que grande utiliza _ para separar los dígitos 1_000_000_000; esto es una característica de C23 que ayuda a la legibilidad, pero el compilador lo trata como el valor entero 1000000000.

Al trabajar con literales enteros, es vital observar octal = 0377. El prefijo 0 le indica al compilador que el número está en base 8. Si tu intención era escribir el número “cero treinta y siete”, el compilador interpretará un valor totalmente distinto. Para los números de punto flotante, hex_float utiliza la notación científica hexadecimal 0x1.p3 de C99, que es extremadamente útil cuando necesitas precisión exacta que el sistema decimal no permite.

En el caso de los strings, la variable mensaje se inicializa con "Hola, " "Mundo". Aquí no hay un operador de suma; es el analizador léxico el que reconoce dos literales de cadena adyacentes y los fusiona en un único token de cadena en la memoria antes de que el programa se ejecute.

El error frecuente
Un error clásico para principiantes es confundir la base decimal con la octal al usar el prefijo 0.

int valor_erroneo = 012; // ¿Es doce o es diez?

En C, esto no es 12, sino 10 en base decimal (porque 12 en octal es 1*8 + 2 = 10). Este error es especialmente peligroso porque es sintácticamente válido, por lo que el compilador no lanzará un error, pero tu lógica fallará silenciosamente. Para evitarlo, si quieres un cero a la izquierda, usa siempre el prefijo 0x para hexadecimal o simplemente escribe el número decimal sin el cero inicial. Herramientas como UBSan (Undefined Behavior Sanitizer) no siempre detectarán esto porque no es un comportamiento indefinido, es simplemente un error de lógica de base numérica.

12

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio