ELEMENTOS LÉXICOS DE C
Los elementos léxicos del lenguaje C son los
que conforman el código fuente de un programa. Estos elementos son llamados
tokens. Existen cinco tipos de tokens: Palabras
claves, identificadores, constantes, operadores y separadores. El espacio
en blanco requiere en algunos casos tokens separados.
PALABRAS CLAVE
Las palabras claves son identificadores
especiales reservados para uso como parte del lenguaje de programación en sí
mismo. No se pueden usar estas palabras claves para ningún otro propósito.
Aquí hay una lista de las palabras claves reconocidas por el ANSI C89:
Aquí hay una lista de las palabras claves reconocidas por el ANSI C89:
auto break case char const continue default do double else enum
extern float for goto if int long register return short signed
sizeof static struct switch typedefunion unsigned void volatile while
El ISO C99 agrego las siguientes palabras
claves:
inline _Bool _Complex _Imaginary
Y las extensiones GNU agregan estas palabras
claves:
__FUNCTION__ __PRETTY_FUNCTION__ __alignof __alignof__ __asm
__asm__ __attribute __attribute__ __builtin_offsetof
__builtin_va_arg __complex __complex__ __const __extension__
__func__ __imag __imag__ __inline __inline__ __label__ __null
__real __real__ __restrict __restrict__ __signed __signed__
__thread __typeof __volatile __volatile__
IDENTIFICADORES
Los identificadores son secuencias de
caracteres usados para nombrar variables, funciones, nuevos tipos de datos y
macros del preprocesador. Se pueden incluir letras, dígitos decimales
y el carácter de subrayado '_' en los identificadores. El
primer carácter de un identificador no puede ser un dígito.
Palabras en minúscula y mayúscula son distintas, por ejemplo foo y FOO son dos identificadores diferentes.
Palabras en minúscula y mayúscula son distintas, por ejemplo foo y FOO son dos identificadores diferentes.
CONSTANTES
Una constante es un valor literal numérico o
carácter, como 5 o 'm'. Todas las constantes son de un tipo en particular; se
puede usar un casting explicito para especificar el tipo de constante o dejar
al compilador usar el tipo por defecto basado en el valor de la constante.
Constantes enteras
Una constante entera es una secuencia de dígitos
con un prefijo opcional que denota la base de un número. Si la secuencia de
dígitos es precedida por 0x o 0X, entonces la constante es considerada como un
hexadecimal (base 16). El hexadecimal puede tomar los valores de 0 a 9 y las
letras de A a F. Algunos ejemplos:
0x2f
0x88
0xAB43
0xAbCd
0x1
Si el primer dígito es 0 (cero) y el siguiente carácter no es 'x' o 'X', entonces la constante es considerada como Octal (base 8). Los valores octales pueden solamente usar dígitos de 0 a 7. Algunos ejemplos:
057
012
03
0241
Si la secuencia de dígitos es precedida por
0b, entonces la constante es considerada como un binario (base 2). El binario
puede tomar los valores de 0 y 1. Algunos ejemplos:
0b00000001
0b10101010
0b11111111
0b11001100
En otros casos la secuencia de dígitos es asumida como decimal (base 10). Los valores decimales pueden usar los dígitos de 0 a 9. Algunos ejemplos:
459
23901
8
12
Hay varios tipos de datos enteros como enteros cortos, enteros largos, enteros con signo y enteros sin signo. Para forzar que la constante entera sea de tipo long y/o unsigned, se debe colocar una o más letras al final de la constante.
u
U
Tipo entero sin signo
l
L
Tipo entero long
Por ejemplo, 45U es una constante entera sin signo. Se puede combinar letras: 45UL es una constante entera long sin signo. Las letras pueden ser usadas en cualquier orden.
U
Tipo entero sin signo
l
L
Tipo entero long
Por ejemplo, 45U es una constante entera sin signo. Se puede combinar letras: 45UL es una constante entera long sin signo. Las letras pueden ser usadas en cualquier orden.
Constantes carácter
Una constante carácter es usualmente un
carácter simple encerrado con comillas simples, como 'Q'. Una constante
carácter es de tipo entero por defecto.
Algunos caracteres, como la comilla simple, no pueden ser representados usando solamente un carácter. Para representar estos caracteres existen varias secuencias de escape que pueden ser usados:
\\ Backslash
\? signo de interrogación
\' Comilla simple
\" Comilla doble
\a Alerta audible
\b Espacio
\e <ESC>
\f Nueva hoja de papel
\n Nueva línea
\r Retorno
\t Tabulación horizontal
\v Tabulación vertical
\o, \oo, \ooo Número octal
\xh, \xhh, \xhhh,... Número hexadecimal
Para usar cualquier secuenciad de estos caracteres de escape, la secuencia debe estar cerrada en comillas simples y tratarlo como si fuere cualquier otro carácter. Por ejemplo la letra m es 'm' y la nueva línea es '\n'.
La secuencia de escape de un número octal es el carácter backslash seguido por uno, dos o tres dígitos octales (0 a 7). Por ejemplo, 101 es el equivalente octal de 65, el cual es el código ASCII del carácter 'A'. Así, la constante carácter '\101' es lo mismo que el carácter constante 'A'.
Algunos caracteres, como la comilla simple, no pueden ser representados usando solamente un carácter. Para representar estos caracteres existen varias secuencias de escape que pueden ser usados:
\\ Backslash
\? signo de interrogación
\' Comilla simple
\" Comilla doble
\a Alerta audible
\b Espacio
\e <ESC>
\f Nueva hoja de papel
\n Nueva línea
\r Retorno
\t Tabulación horizontal
\v Tabulación vertical
\o, \oo, \ooo Número octal
\xh, \xhh, \xhhh,... Número hexadecimal
Para usar cualquier secuenciad de estos caracteres de escape, la secuencia debe estar cerrada en comillas simples y tratarlo como si fuere cualquier otro carácter. Por ejemplo la letra m es 'm' y la nueva línea es '\n'.
La secuencia de escape de un número octal es el carácter backslash seguido por uno, dos o tres dígitos octales (0 a 7). Por ejemplo, 101 es el equivalente octal de 65, el cual es el código ASCII del carácter 'A'. Así, la constante carácter '\101' es lo mismo que el carácter constante 'A'.
Números reales constantes
Una número real constante es una valor que
representa un número fraccional (punto flotante). Este consiste en una secuencia
de dígitos la cual representa la parte entera, un punto decimal y una secuencia
de dígitos la cual representa la parte fraccional.
La parte entera o la parte fraccional pueden ser omitidas, pero no ambas. Aquí hay algunos ejemplos:
La parte entera o la parte fraccional pueden ser omitidas, pero no ambas. Aquí hay algunos ejemplos:
double a, b, c, d, e, f;
a
= 4.7;
b
= 4.;
c
= 4;
d
= .7;
e
= 0.7;
Un número real constante puede ser seguido
por un e o E y un exponente entero. El exponente puede ser positivo o
negativo.
double x, y;
x
= 5e2; /* x es 5 * 100, or 500.0. */
y =
5e-2; /* y es 5 * (1/100, or 0.05. */
Se puede colocar una letra al final de un número real constante para hacer que sea de un tipo particular. Si se coloca la letra F o f, el número real constante es de tipo flotante. Si se coloca un L o l, el tipo es long double. Si no se coloca una letra, entonces el tipo es double.
Constante cadena
Una constante tipo cadena es una secuencia de
cero o más caracteres, dígitos, y secuencias de escape encerradas en doble
comillas. Una constante cadena es de tipo "arreglo de caracteres".
Todas las constantes cadenas contienen un carácter de terminación null ( \0)
como último carácter. Las cadenas son almacenadas como arreglos de caracteres,
con un atributo de tamaño inherente. El carácter de terminación null indica a
las funciones que procesan cadenas la terminación de las cadenas.
Una cadena no puede contener doble comillas. Para incluir las doble comillas en una cadena se usa la secuencia de escape \". Aquí hay algunos ejemplos:
Una cadena no puede contener doble comillas. Para incluir las doble comillas en una cadena se usa la secuencia de escape \". Aquí hay algunos ejemplos:
/*
Esta es una cadena simple. */
"tutti frutti ice cream"
/*
Esta cadena será concatenada, como la de arriba. */
"tutti " "frutti" " ice "
"cream"
/*
El uso de dos secuencias de escape. */
"\"hello, world!\""
Si una cadena es muy larga para llenar una línea, se puede usar un backslash \ para dividir en líneas separadas.
"Este es un ejemplo de una cadena divida por \
dos líneas."
Las cadenas adyacentes son automáticamente concatenadas, así si se escribe dos cadenas separadas por múltiples líneas, estas serán unidas.
"Este es un ejemplo de una cadena divida por "
"dos líneas."
Es lo mismo que
"Este es un ejemplo de una cadena divida por \
dos líneas."
Insertar un carácter de nueva línea en la
cadena, hace que la cadena se impresa en dos diferentes líneas.
printf ("potato\nknish");
Imprime
potato
knish
OPERADORES
Los operadores son
un tipo de tokens que pueden aparecer en las expresiones, e indican al
compilador la realización de determinadas operaciones matemáticas, lógicas y
numéricas . Se aplican a variables u otros objetos denominados operandos y
su efecto es una combinación de las siguientes acciones:
- Producir un resultado-valor
- Alterar un operando
- Designar un objeto o función.
Ejemplos
y = a + b;
En esta sentencia,
el operador suma + produce un valor nuevo, pero no altera
ninguno de los operandos (a y b); a su vez, el nuevo valor es
asignado a la variable y mediante el operador de asignación. En este caso
el operando de la izquierda sí se ve alterado.
x++;
Aquí el operador
postincremento ++ produce un nuevo valor que es aplicado sobre el
propio operando, de forma que queda alterado. Cuando un operador altera un
operando se dice que tiene efectos laterales.
Nota: por lo
general, los operadores aparecen a la derecha de expresiones de asignación (por
ejemplo: y = 2 * y + x), pero en ocasiones estos "efectos laterales"
se utilizan para conseguir expresiones muy compactas y de un cierto nivel de
sofisticación, que incluso no necesitan del operador de asignación para
producir el resultado. En estos casos su lógica es un poco más difícil de
seguir que cuando estos efectos no se utilizan directamente
(Ver ejemplo).
z = (*fptr)(x, y);
Aquí, el operador
de indirección * es aplicado sobre el operando fptr que es
un puntero-a-función. El resultado es un designador de función al que se aplica
el operador ( ) de invocación de función con dos
operandos x e y que actúan como argumentos. A su vez el
resultado de este operador (invocación de función) es utilizado como argumento
derecho del operador de asignación = que finalmente modifica uno de
sus operandos (el operando izquierdo z).
Clasificación
C++ dispone de un
conjunto muy rico de operadores que se pueden clasificar
en unitarios, binarios y ternarios, según que necesiten
uno, dos o tres operandos. Los operadores unitarios (denominados
también unarios) se clasifican en dos tipos según la posición del operador
(representado aquí por @) respecto del operando (representado aquí
por n):
@n: Operador prefijo.
Ejemplo: ++x
n@:
Operador posfijo. Ejemplo: x++
Antes de seguir refiriéndonos a ellos, tal vez sean procedentes un par observaciones que más adelante nos ayudarán a comprender mejor algunos conceptos:
- Los operadores pueden (en cierta forma)
considerarse como funciones que tienen un álgebra un tanto especial. De
hecho, al tratar la sobrecarga de operadores, veremos que precisamente la
forma en que se definen es mediante una función, la función-operador. En
este sentido podríamos imaginar que la expresión y = a + b es
otra forma de representar algo como: y = suma(a, b). Del mismo modo,
la asignación x = y sería algo así: asigna(x, y). Siguiendo
con nuestra analogía, podríamos suponer que los operadores unitarios,
binarios y ternarios serían funciones que aceptarían unos, dos o tres
argumentos respectivamente y que la sobrecarga de operadores no es sino
una forma encubierta de sobrecarga de funciones.
- Aunque las funciones C++ se designan con
identificadores (nombres) que siguen las reglas generales ya señaladas ,
estas seudo-funciones se identifican con símbolos
( +, =, ::, *, ->, etc.) . Muchos de ellos
están compuesto de un solo token (que puede estar
repetido + y ++) aunque los hay de dos. Estos últimos
son: new [], delete [], () y [].
- Antes de realizar la operación encomendada, los
operadores pueden modificar el tipo de los operandos para que sean
homogéneos, de forma que la operación pueda realizarse. Por ejemplo, al
indicar i + f donde i sea un entero
y f un float. Estas promociones se denominan conversiones
estándar y son realizadas automáticamente por el compilador, pero deben ser
tenidas en cuenta para evitar sorpresas.
En general
los operadores aceptan un tipo de operando determinado y específico,
produciendo y/o modificando un valor de acuerdo con ciertas reglas, pero C++
permite redefinir la mayoría de ellos. Es decir, permite que puedan aceptar
otro tipo de operandos y seguir otro comportamiento sin que pierdan el sentido
y comportamiento originales cuando se usan con los operandos normales (los
tipos básicos preconstruidos en el lenguaje). Esta circunstancia recibe el
nombre de sobrecarga del operador.
PUNTUADORES
Los signos de puntuación del lenguaje C++
juegan el mismo papel que sus homónimos en el lenguaje natural
escrito. Conocidos también como puntuadores, son los que se
citan a continuación. La mayoría de ellos tienen un doble uso y en
ocasiones funcionan también como operadores.
[ ] ( ) {
} , ; : ... * =
# ! % ^ & – + |
~ \ ' " < > ? .
/
Corchetes [
]
Los corchetes indican subíndices de matrices
uni y multi dimensionales.
char ch, str[] = "Cadena
de caracteres";
int mat[3][4]; // Matriz
de 3 x 4
ch = str[3]; // cuarto elemento
ch = str[3]; // cuarto elemento
Paréntesis (
)
Los paréntesis sirven para agrupar
expresiones; alterar la precedencia normal de los operadores y su
asociatividad; aislar expresiones condicionales; indicar llamadas a funciones,
y señalar los parámetros de estas. La sintaxis de C++ exige indefectiblemente
el uso de paréntesis en múltiples ocasiones. En los ejemplos que siguen se
muestran algunos usos.
d = c * (a + b);
// modifica la precedencia normal
if (d == z) ++x;
// imprescindible en la sentencia if
for (x =1; x<10; x++) //
imprescindible en la sentencia for
func();
// señala llamada a función
int
func();
// declara función
int (*fptr)();
// declara puntero a función
fptr = func;
// asigna valor al puntero.
Observe que en el último caso, la ausencia de
paréntesis equivale a &func
Se recomienda el uso de paréntesis en las
macro-definiciones para evitar problemas potenciales en la expansión. Por
ejemplo:
#define CUBO(x) ((x) * (x) * (x))
Llaves {
}
Los pares de llaves { } señalan
el comienzo y final de una sentencia compuesta, es decir, bloques de código
(grupos de sentencias que son tratadas como una unidad). Constituyen el
segundo paso (después de las sentencias) en la estructuración y
compartimentación del código C++:
if (d == z)
{
++x;
func();
}
Un bloque es una sentencia compuesta, se trata de una sucesión (que puede estar vacía) de sentencias delimitadas por un par de corchetes { }. Desde el punto de vista sintáctico, un bloque puede ser considerado como una sola sentencia. Juega un papel importante en el ámbito (scope) de los identificadores, puesto que un identificador declarado dentro de un bloque tiene un ámbito que comienza en el punto de la declaración y termina en el corchete final. Sin embargo, el mismo identificador puede ser ocultado por otro del mismo nombre declarado en un bloque interior al primero.
Dentro de las posibilidades de memoria, los
bloques pueden ser anidados a cualquier nivel (profundidad).
Después del corchete de cierre } no se
necesita el punto y coma ; de fin de sentencia
if (statement)
{...}; //
punto y coma ilegal !!
else
Nota: las llaves sirven también en C++ para
otros usos distintos de la pura delimitación de bloques de código. Por ejemplo,
en la definición de estructuras, uniones y clases, en cuyo caso si puede
ser necesaria la inclusión del punto y coma después de la llave de cierre }.
Coma ,
La coma como puntuador se utiliza para
separar los elementos en las listas de parámetros de una función:
void func(int n, float f, char ch);
La coma se usa también como un operador en
las expresiones con coma . Es posible mezclar los dos usos
(separador en lista de parámetros y operador), pero deben usarse paréntesis
para distinguirlos.
Punto y coma ;
El punto y coma ; es el
signo de fin de sentencia. Cualquier expresión legal C++ terminada por un punto
y coma (incluyendo la expresión vacía - un punto y coma aislado-) es
interpretado como una sentencia, conocidas como sentencia-expresión . La
expresión se evalúa y el resultado se descarta; si no tiene efectos
colaterales, C++ la ignora.
a + b;
// evalúa a + b, descarta el resultado
++a; //
efecto lateral en 'a', se descarta el valor ++a
;
// expresión vacía = sentencia nula
El punto y coma se usa a veces para crear
sentencias nulas:
for (i = 0; i < n; i++)
{
; //
sentencia nula (hacer nada)
}
Dos puntos :
Los dos puntos se utilizan para señalar sentencias
etiquetadas :
comienzo: x=0;
// comienzo es la etiqueta
...
goto comienzo;
Puntos
suspensivos ...
Los puntos suspensivos, también
llamados elipsis, son tres puntos, seguidos y sin
espacios intermedios; tienen varios usos en C++.
Se utilizan en las relaciones de argumentos
formales de las funciones, cuando estas pueden aceptar un número variable de
argumentos o pueden ser de tipo variable . Por ejemplo:
void func(int n, char ch,...);
Este prototipo de función declara
que func está definida de modo que debe ser llamada con, al menos,
dos argumentos: un int y un char. Además puede
tener un cierto número de argumentos adicionales (puede omitirse la coma antes
de la elipsis).
Se utiliza también para indicar que un
manejador de excepciones ("handler") puede capturar una excepción de
cualquier tipo. Ejemplo:
try
{ // bloque-intento
...
}
catch (...) { // captura
cualquier excepción
cout << "Se ha producido
una excepción!" << endl;
...
}
Nota: como podéis ver, en ocasiones, mi uso
particular en los ejemplos de los tres puntos, es para indicar cualquier número
de sentencias. Espero que no sea motivo de confusión. Desde luego, en el caso
anterior sería más correcta la notación:
try
{ //
bloque-intento
// ...
}
catch (...) { // captura
cualquier excepción
cout << "Se ha producido
una excepción!" << endl;
// ...
}
Asterisco *
El asterisco * puede ser
utilizado en C++ de tres formas: como una declaración de tipo de variable
(variable de puntero ; como operador de indirección (también
llamado operador de de referencia y como operador de
multiplicación.
Ejemplos:
char* char_ptr;
// declara puntero a carácter
x = *int_ptr;
// operador de indirección
l = 2 * 3.14 *
r; // operador multiplicación
Signo igual =
El signo igual = separa la
declaración de variables de las listas de inicialización:
char array[5] = { 1, 2, 3, 4, 5 };
Recordemos que, al contrario que en C, donde
las declaraciones no pueden estar precedidas por ningún código, deben ir al
principio, en C++, las declaraciones de cualquier tipo pueden aparecer en
cualquier punto del código (con algunas restricciones).
En la lista de argumentos de una función, el
signo igual indica el valor por defecto para un parámetro:
int f(int i = 0) { ... } // el
valor por defecto de k es cero
El signo igual es también utilizado
como operador de asignación. Ejemplo:
x = y;
z += 5;
Almohadilla #
Si la almohadilla # aparecen
en el primer carácter (distinto de espacio en blanco) de una línea,
señala directivas de preproceso . En este caso, es
un operador específico de la fase de preproceso del código fuente.
Significa una opción del preprocesador que no tiene porqué estar asociada
necesariamente a generación de código. Las directivas se sitúan
generalmente al comienzo del programa, aunque legalmente pueden aparecer en
cualquier punto.
Ejemplos de directivas de preproceso:
# (null directive)
#define NULO \0
#include <stdio.h>
SINTAXIS
La sintaxis de un lenguaje de programación es
el conjunto de reglas que debemos seguir para que el compilador sea capaz de
reconocer nuestro programa como un programa C válido.
SINTAXIS DEL LENGUAJE C
* Los bloques de código se marcan con las llaves {…}. Son equivalentes al inicio y fin del pseudocódigo.
* Todas las instrucciones terminan con un punto y coma ( ; )
* Los identificadores de variables, funciones, etc., no pueden empezar con un número ni contener espacios o símbolos especiales, salvo el de subrayado ( _ )
* Los caracteres se encierran entre comillas simples ( ‘…’ )
* Las cadenas de caracteres se encierran entre comillas dobles ( “…” )
* El lenguaje es sensitivo a las mayúsculas. Es decir, no es lo mismo escribir main() que MAIN() o Main
El punto y coma
El punto y coma es uno de los símbolos más
usados en C, C++; y se usa con el fin de indicar el final de una línea de
instrucción. El punto y coma es de uso obligatorio.
Ejemplo
´´´´´´
Ejemplo
´´´´´´
clrscr(); //Limpiar pantalla, funciona solo
con la librería conio de Borland C++
x = a + b;
El punto y coma se usa también para separar
contadores, condicionales e incrementadores dentro de un sentencia for
ejemplo
ejemplo
for (i=0; i < 10; i++) cout << i;
Separador de bloque
Un bloque es un grupo de instrucciones
contenidas entre los símbolos de llave izquierda '{' y llave derecha '}', su
uso es obligatorio en la definición de funciones, y opcionalmente pueden
aparecer en cualquier otra parte del programa.
Ejemplos
Ejemplos
// aquí, las llaves son opcionales ya que
dentro
// del ciclo for hay solamente una instrucción.
for (i=0; i < 10; i++) { cout << i; }
Espacios y tabuladores
Usar caracteres extras de espaciado o
tabuladores (caracteres tab ) es un mecanismo que nos permite
ordenar de manera más clara el código del programa que estemos escribiendo, sin
embargo, el uso de estos es opcional ya que el compilador ignora la presencia
de los mismos. Por ejemplo, el segundo de los ejemplos anteriores se podría
escribir como:
for (int i=0; i < 10; i++) { cout << i * x; x++; }
y el compilador no pondría ningún reparo.