Anda di halaman 1dari 30

Instituto Tecnológico y de Estudios Superiores de Monterrey

Curso de Lenguaje C
Ing. Enrique Alejandro Navarrete Paredes

Abril de 1998
Índice
1. Introducción...........................................................................................................1
2. Estructura de un programa en C.............................................................................1
2.1. Instrucciones para el compilador...............................................................1
2.2. Definición de estructuras............................................................................2
2.3. Definición de variables...............................................................................2
2.4. Funciones...................................................................................................2
2.5. Programa principal.....................................................................................2
3. Tipos y operadores.................................................................................................3
3.1. Tipos..........................................................................................................3
3.2. Estructuras.................................................................................................4
3.3. Uniones......................................................................................................5
3.4. Enumeraciones...........................................................................................5
3.5. Modificadores de almacenamiento.............................................................6
Modificador "extern"...............................................................................6
Modificador "auto"..................................................................................6
Modificador "register".............................................................................6
Modificador "const"................................................................................6
Modificador "volatile".............................................................................7
Modificador "static".................................................................................7
3.6 Operadores..................................................................................................7
Operadores aritméticos............................................................................7
Operadores de relación y lógicos.............................................................7
Operadores de incremento y decremento................................................8
Operadores para manejo de bits...............................................................8
Operadores de asignación y expresiones.................................................8
Precedencia y asociatividad de operadores..............................................9
Conversión de tipos.................................................................................10
4. Control de flujo......................................................................................................10
4.1. if-else..........................................................................................................11
Expresiones condicionales.......................................................................11
4.2. else-if..........................................................................................................12
4.3. switch.........................................................................................................12
4.4. while...........................................................................................................13
4.5. for...............................................................................................................13
4.6. do-while.....................................................................................................14
4.7. break y continue.........................................................................................14
5. Funciones................................................................................................................15
6. Apuntadores............................................................................................................16
7. Compilador cc........................................................................................................18
8. El preprocesador de C............................................................................................18
8.1. Unión de líneas...........................................................................................18
8.2. Definición y expansión de macros..............................................................18
8.3. Inclusión de archivos..................................................................................19
8.4. Compilación condicional............................................................................19
8.5. Control de línea..........................................................................................20
8.6. Generación de errores................................................................................20
8.7. Pragmas......................................................................................................20
8.8. Directiva nula.............................................................................................21
8.9. Nombres predefinidos................................................................................21
Apéndice A Compilador XL C.................................................................................22
USO:.................................................................................................................22
DESCRIPCIÓN:...............................................................................................22
OPCIONES:......................................................................................................22
1. Introducción
El lenguaje C fue hecho por Brian W. Kerninghan y Dennis M. Ritchie a mediados de los 70's, con
el objeto de desarrollar el sistema operativo UNIX para la computadora PDP-11. Desde entonces
a la fecha ha tenido una amplia aceptación dentro del área de la programación debido a su
flexiblidad, tamaño y portabilidad.

Es un lenguaje de bajo-medio nivel, que permite el acceso al hardware de la computadora y a su


vez el empleo del modelo de programación estructurada, de manera que se puede hacer uso
eficiente de los recursos con los que cuenta un equipo de cómputo.

El presente curso tiene como objetivo hacer un estudio completo sobre el lenguaje, considerando
su sintaxis, estructura y uso de sus instrucciones.

2. Estructura de un programa en C
Un programa en C, consta de varias secciones en donde se determinarán que variables y funciones
tendrá el programa, así como la tarea que tendrá que realizar. Su estructura está determinada por
las partes siguientes:

· Instrucciones para el compilador


· Definición de estructuras
· Definición de variables
· Funciones
· Programa principal

2.1. Instrucciones para el compilador


Las líneas que se escriben en esta sección indican al compilador la realización de diferentes tareas
como: la definición de nombres, tomas de decisión durante la compilación, macros e inclusión de
archivos entreotras.

Todas las líneas del preprocesador inician con el carácter '#'. Por ejemplo:

#include<stdio.h>
#define PI 3.1416 /* Donde PI es el nombre de la etiquieta y su 
valor es 3.1416 */

Donde todos los caracteres que se encuentren entre "/*" y "*/", son tomados como comentarios y
no tienen efecto para la compilación.

2.2. Definición de estructuras

1
En esta área se definen todas las estructuras que requiera el programa. Donde una estructura es la
colección de variables para la representación del problema que se está tratando. Por ejemplo:

struct esfera
{
float radio;
float volumen;
};

2.3. Definición de variables


Una vez creados los tipos y estructuras, se procede a la definición de las variables, que son
etiquetas con las cuales se tiene acceso a localidades de memoria para el almacenamiento de
información durante la ejecución del programa.

Un ejemplo definición de variable es:

struct esfera A;

2.4. Funciones
Las funciones son conjuntos de instrucciones encargadas de la realización de tareas específicas. .
Su existencia permite la respresentación del problema en función del modelo de programación
estructurada.

Una función que calcula el volumen de una esfera se presenta enseguida.

void volum(void)
{
A.volumen= (4.0 / 3.0) * PI * A.radio * A.radio * A.radio;
}

2.5. Programa principal


El programa principal contiene las instrucciones y llamadas a funciones que se ejecutan en primera
instancia. Siempre se tiene el nombre de "main".

El programa principal para el cálculo del volumen de una esfera puede ser el siguiente:

void main(void)
{
printf("\n\t Deme el radio de la esfera:  ");
scanf("%f",&A.radio);
volum();
printf("\n\t El volumen de la esfera con radio %f, es: 
%f\n",A.radio,\

2
       A.volumen); 
}

Observación: Es de suma utilidad usar tabuladores para la claridad del programa.

3. Tipos y operadores

3.1. Tipos
Las variables usadas en lenguaje C, pueden ser de varios tipos. Éstos, definirán el tamaño en bytes
de cada variable. Los tipos que existentes son:

void Sin valor


char Caracter
short Entero corto
int Entero
long Entero largo
float Flotante
double Flotante de doble precisión
signed Usa signo
unsigned Sin signo

El tipo void permite declarar funciones que no regresan valores y también para la declaración de
apuntadores genéricos, es decir capaces de apuntar a cualquier tipo de variable.

La declaración de una variable emplea la sintáxis siguiente:

Tipo nombre_variable, nombre_variable, nombre_variable = constante;

En la declaración de variables se pueden definir una o más variables del mismo tipo en el mismo
renglón, por ejemplo:

int numero, altura, profundidad;

Todas las líneas terminan con punto y coma (;). También se les puede asignar un valor inicial en el
momento de la definición. Por ejemplo:

char letra_inicial = 'J';
float elevacion = 2.43, x = 4.0;
Es importante mencionar que en el nombre de la variable se pueden emplear letras minúsculas,
mayúsculas y el carácter '_' (línea de subrayado).

También se pueden definir arreglos unidimensionales y multidimensionales.

char nombre[30];
unsigned char meses[2][12] = 
{
{31,28,30,31,30,31,30,31,31,30,31,30,31},

3
{31,28,30,31,30,31,30,31,31,30,31,30,31}
};

Las cadenas de caracteres se representan usando doble comilla, por ejemplo: "Es un día soleado",
mientras que para un solo carácter se emplea la comilla, por ejemplo: 'a', 'b', 'z'. Las cadenas de
caracteres en C, se terminan con el carácter especial '\0'. Otros caracteres especiales (también se
les denomina secuencias de escape) son:

'\a' carácter de alarma


'\b' retroceso
'\f' avance de hoja
'\n' nueva línea
'\r' regreso de carro
'\t' tabulador horizontal
'\v' tabulador vertical
'\\' diagonal invertida
'\?' interrogación
'\'' apóstrofo
'\"' comillas
'\ooo' número octal
'\xhh' número hexadecimal
'\0' carácter nulo

3.2. Estructuras
Una estructura es una colección de variables que se agrupan bajo un una sola referencia. La
sintáxis general es:

struct nombre_estructura {
elemento 1;
elemento 2;
.
.
.
} variable_struct;

Donde la palabra reservada es "struct", el nombre del conjunto de variables se pone en


"nombre_estructura", se abre una llave y enseguida se ponen las variables (cada elemento, usa la
declaración de variables usada en el punto 3.1); al terminar de definir todos los elementos, se
cierra la estructura con una llave. Hasta aquí, sólo se ha definido la estructura, sin embargo no hay
ninguna instancia (creación física) de la misma. Por tanto se hace necesario definir una variable
cuyo tipo sea la estructura predefinida.

Usemos una estructura ya vista:

struct esfera
{
float radio;
float volumen;
};

4
struct esfera A;

Para accesar un campo de la estructura, se usa el nombre de la variable, seguida por un punto y
después por el nombre del campo que se va a usar.

A.radio = 4.0;
A.volumen = 4332.8998;

3.3. Uniones
Existe la posibilidad de usar de manera más eficiente la memoria de la computadora, esto se puede
lograr empleando la definición de unión. La sintáxis es similar a la de la estructura.

union nombre_de_la_union {
elemento 1;
elemento 2;
.
.
.
} variable_union;

La diferencia estriba, en que, en este caso las variables se solapan. Por ejemplo:

union libros {
char inicial;
int num;
} lib;

En este caso la unión emplea 2 bytes para la variable "num", y uno de esos bytes se emplea para la
variable "inicial", por tanto, no hay 3 bytes en la definición, sino sólo dos.

3.4. Enumeraciones
La enumeración es una lista de valores posibles que puede tomar una variable. Por ejemplo:

enum ciudades México, Zacatecas, Guanajuato, Nayarit;

enum ciudades ciud;

Donde "ciud" sólo puede tomar cualquiera de los nombre dados en la declaración previa.

3.5. Modificadores de almacenamiento


Con los modificadores de almacenamiento se altera la forma en que se crea el
almacenamiento. Los modificadores son: extern, auto, register, const, volatile

5
y static.

Modificador "extern"
Se emplea cuando un programa se encuentra dividido en varios archivos. Como las variables sólo
se definen una vez, se hace necesario hacer referencia de ellas en los archivos que así lo requieran.

La sintáxis es:

extern tipo la_variable; /* Se debe indicar también el tipo de la 
variable o función */

Se dice que este tipo de variables tienen "liga externa".

Modificador "auto"
Todas las variables son "auto" por omisión, y son objetos locales a un bloque y al salir de éste son
descartadas.

Modificador "register"
Los objetos declarados como "register" son automáticos y sus valores se almacenan en registros
del microprocesador de la computadora.

Modificador "const"
Las variables de tipo "const" no pueden cambiarse por el programa durante la ejecución.

Una variable "const" recibirá su valor desde una inicialización explícita o por medio de alguna
dependencia del hardware.

Modificador "volatile"
Las variables modificadas por "volatile" indican que éstas pueden ser modificadas de forma no
explícita por el programa. Por ejemplo: se podría guardar la hora exacta en una variable y que la
asignación la hiciera la rutina de atención a la interrupción del reloj.

Modificador "static"
Se usa para mantener una variable local en existencia durante la ejecución de un programa, de
manera que no se tiene que crear y destruir cada vez que se encuentra a la rutina donde está
declarada.

3.6 Operadores

6
Los tipos de operadores que existen son: aritméticos, de relación y lógicos, de incremento y
decremento, para manejo de bits, de asignación y expresiones, expresiones condicionales.

Operadores aritméticos
Los operadores aritméticos binarios son '+', '-', '*', '/' y '%'. Su significado se muestra a
continaución:

+ Suma de dos operandos


- Resta entre dos operandos
* Multiplicación de dos operandos
/ División entre dos operandos
% Módulo entre dos operandos. Da el residuo de la división
resultante entre el operando1 (numerador) y el operando2
(denominador).

La sistáxis es:

operando1 operador operando2

La división entera truca cualquier parte fraccionaria.

Operadores de relación y lógicos


Los operadores de relación son: '>', ">=", '<', "<=", "==" y "!=".

> Mayor que


>= Mayor o igual
< Menor que
<= Menor o igual
== Idéntico
!= Diferente a

Los operadores lógicos son: "&&" y "||"

&& Y
|| Ó

El resultado del uso de estos operadores puede ser falso o verdadero. Se considera como falso el
valor de cero, y como verdadero, todo aquel valor diferente de cero.

La sistáxis es:

operando1 operador operando2

7
Operadores de incremento y decremento
Los operadores de incremento y decremento, añaden o quitan una unidad al operando que están
afectando, respectivamente. De tal manera que:

++i; es equivalente a: i=i+1; y después se emplea el valor de i


i++; es equivalente a: se usa el valor de i, enseguida se incrementa
--i; significa: i=i-1; y después se usa el valor de i
i--; significa: se usa el valor de i, enseguida se decrementa en uno

Como nota importante se debe poner énfasis en la precedencia de cada expresión.

Operadores para manejo de bits


Los operadores para manejo de bits son:

& AND de bits. Ejemplo: 0x0F & 0xFE => 0x0E


| OR inclusivo de bits. Ejemplo: 0x1E | 0x01 => 0x1F
^ OR exlusivo de bits. Ejemplo: 0xF0 ^ 0x02 => 0xF2
<< corrimiento a la izquierda. Ejemplo 0x02 << 2 => 0x08
>> corrieminto a la derecha. Ejemplo 0x04 >> 2 => 0x01
~ complemento a uno (unario). Ejemplo ~0xF0 => 0x0F

Operadores de asignación y expresiones


El operador de asignación '=', se usa como se muestra enseguida:

x = 5 + 4;

Y puede intrepetarse como: el resultado de sumar 5 + 4 se asigna a la variable x.

También se puede usar para la suma de dos variables y que el resultado quede en una tercera. Por
ejemplo:

x = y / z;

Supongamos,

x = 4;

Cuando se tiene x = x + 5, primero se suma a x el 5 que implica que se obtenga el número 9, y


después se asigna a x. Por tanto el valor final de x es idéntico a 9 (x == 9).

Otra forma de expresar lo anterior es: x += 5 que es equivalente a x = x + 5. De esta manera "+="
es un operador de asignación.

8
En general se puede decir que:

expresión1 op= expresión2

equivale a

expresión1 = (expresión1) op (expresión2)

Precedencia y asociatividad de operadores


La precedencia y asociatividad de los operadores se muestra en la tabla siguiente.

Nota: Los operadores que están en la misma línea tienen la misma precedencia; los renglones están
en orden de precendencia decreciente, por ejemplo, '*', '/', y '%' todos tienen la misma precedencia,
la cual es más alta que la de '+' y '-' binarios. El "operador" ( ) se refiere a la llamada a una función.

Operadores Asociatividad

() [] izquierda a derecha
! ~ ++ -- + - * & (tipo) sizeof derecha a izquierda
* / % izquierda a derecha
+ - izquierda a derecha
<< >> izquierda a derecha
< <= > >= izquierda a derecha
== != izquierda a derecha
& izquierda a derecha
^ izquierda a derecha
| izquierda a derecha
&& izquierda a derecha
|| izquierda a derecha
?: derecha a izquierda
= += -= *= /= %= &= ^= |= <<= >>= derecha a izquierda
, izquierda a derecha

Conversión de tipos
Cuando un operador tiene operandos de tipos diferentes, éstos se convierten a un tipo común de
acuerdo con un reducido número de reglas. Estas reglas son:

· Si cualquier operando es long double, conviértase el otro a long double.

· De otra manera, si cualquier operando es double, conviértase el otro a double.

· De otra manera, si cualquier operando es float, conviértase el otro a float.

9
· De otra manera, conviértase char y short a int.

· Después, si cualquier operando es long, conviértase el otro a long.

También se puede convertir de un tipo a otro usando el operador "cast". Que consiste en
anteponer a la variable o función el tipo que se desea. Para ello se usan paréntesis. Por ejemplo:

char caracter;
int entero;

entero = (int) caracter;

4. Control de flujo
Mediante las proposiciones de control de flujo se indica el orden en que se realizará el proceso.
Las expresiones vistas anteriormente, se vuelven proposiciones cuando se terminan con punto y
coma ';'.

Las llaves '{', '}' se emplean para agrupar declaraciones y proposiciones dentro de una proposición
compuesta o bloque.

Para el control del programa existen las proposiciones siguientes: if-else,


else-if, switch, while, for y do-while.

4.1. if-else
La proposición if-else se usa para expresar decisiones. La sintáxis es:

if(expresión)
proposición1;
else
proposición2;

Si la expresión es verdadera, se ejecuta la proposición1, de lo contrario se realiza la proposición2.

No es indispensable el else, es decir, se puede tener una proposición de la forma:

if (expresión)
proposición1;

Se debe hacer notar que la proposición1 o la proposición2, pueden ser proposiciones compuestas
o bloques. Por ejemplo:

10
if( x == 1 )
{
y = r*j;
printf("El resultado de y es: %u", y);
}
else
{
printf("Se tiene un valor incorrecto de x");
printf("Vuelva a repetir los pasos 1 al 8");
}

Expresiones condicionales
Otra forma de escribir la proposición if-else es usando una expresión condicional.

expresión1 ? expresión2 : expresión 3

Que es equivalente a:

if( expresión1 )
expresión2;
else
expresión3;

Nota: Si las expresiones 2 y 3 son compuestas, cada proposición debe estar separada por coma ','.
Por ejemplo:

(A.radio > 4) ?
printf("\n Funciona\n"), printf("A ver??\n")
: printf("\n Es más pequeño");

4.2. else-if
Con esta expresión se complementa la expresión vista en el punto anterior. Su sintáxis es:

if( expresión )
proposición;
else if( expresión )
proposición;
else if( expresión )
proposición;
else if( expresión )
proposición;
else
proposición;

Mediante esta expresión se puede seleccionar una condición muy específica dentro de un
programa, es decir, que para llegar a ella se haya tenido la necesidad del cumplimiento de otras
condiciones.

11
4.3. switch
La proposición switch, permite la decisión múltiple que prueba si una expresión coincide con uno
de los valores constantes enteros que se hayan definido previamente.

Su sintáxis es:

switch( expresión ) {
case exp­const: proposiciones
break;

case exp­const: proposiciones
break;

case exp­const: 
case exp­const: proposiciones
break;

default: proposiciones
}

Se compara la "expresión" con cada una de las opciones "exp-const", y en el momento de


encontrar una constate idéntica se ejecutan las proposiciones correspondientes a ese caso. Al
terminar de realizar las proposiciones del caso, se debe usar la palabra reservada "break" para que
vaya al final del switch.

Si ninguno de los casos cumplen con la expresión, se puede definir un caso por omisión, que
también puede tener proposiciones.

En todos los casos pueden ser proposiciones simples o compuestas. En las compuestas se usan
llaves para definir el bloque.

4.4. while
La proposición "while" permite la ejecución de una proposición simple o compuesta, mientras la
"expresión" sea verdadera. Su sintáxis es:

while( expresión )
proposición

Por ejemplo,

while( (c = getchar())  == 's' || c == 'S' )
printf("\nDesea salir del programa?");

while( (c = getchar())  == 's' || c == 'S' )
{
printf("\nDesea salir del programa?");
++i;

12
printf("\nNúmero de veces que se ha negado a salir: %u",i);
}

4.5. for
La proposición "for" requiere tres expresiones como argumento. Las expresión1 y la expresión3
comúnmente se emplean para asignaciones, mientras que la expresión2 es la condición que se debe
cumplir para que el ciclo "for" se siga ejecutando.

La sintáxis es:

for(expresión1; expresión2; expresión3)
proposición

Ejemplo:

for(i=0; i <= 500; ++i)
printf("\nEl número par  # %i, es: %i", (2*i), i);

4.6. do-while
La proposición "do-while" es similar a la proposición "while", se ejecuta el ciclo mientras se
cumpla la condición dada en "expresión".

La diferencia estriba en que en el "do-while" siempre se evalúa al menos una vez su "proposición",
mientras que en el "while" si no se cumple la "expresión" no entra al ciclo.

Sintáxis:

do
proposición
while( expresión );

Ejemplo:

i=0;
do
{
printf("\nEl número par  # %i, es: %i", (2*i), i);
++i;
}
while( i < 500 );

4.7. break y continue

13
Cuando se quiere abandonar un ciclo en forma prematura debido a que ciertas condiciones ya se
cumplieron, se puede usar la proposición "break". Ésta sirve par las proposiciones "for", "while" y
"do-while".

También se tiene otra proposición relacionada, y esta es el "continue"; su función es la de


ocasionar la próxima iteración del ciclo.

Ejemplos:

for(h=1; h <= 1000; ++h)
{
if( h%5 == 0 )
continue;
printf("Número que no es múltiplo de 5: %i", h);
}

while(1)
{
if( getchar() == '$' )
break;
printf("\nNo puedo parar, hasta que presione \'$\'");
}

5. Funciones
Las funciones son fragmentos de un programa que realizan tareas específicas.Esto permite dar
claridad al programa y facilita su mantenimiento.

La sintáxis de las funciones es:

tipo nombre_función (tipo argumento)
{
expresión1:
expresión2;
expresión3;
.
.
}

El "tipo" determina la clase de variable que regresará la función. Los tipos definidos para las
variables en la sección 3.1 son aplicables a las funciones.

El "nombre_función" deberá ser único en todo el programa y no se podrán usar ni palabras


reservadas del lenguaje, ni funciones ya preestablecidas en las librerías del compilador.

A una función se le pueden pasar argumentos, con el fin de que con esos valores se realicen
cálculos específicos. Los argumentos se separan por comas. Por ejemplo:

void integra(float x, float dx, float lim_inf, float lim_sup)

14
{
.
.
}

El paso de argumentos entre funciones puede ser por valor o por dirección.

Finalmente, las funciones pueden regresar un resultado, es decir, que al finalizar la ejecución de la
función se produjo un dato que se va a usar posteriormente dentro del programa y por ello es
necesario que sea dado como respuesta. Para realizar esto se emplea la palabra reservada "return".
Por ejemplo:

float cuadrado(float x)
{
float y;
y = x * x;
return(y);
}

void main(void)
{
float xx, yy, rr;
.
.
.
rr = sqrt( (cuadrado(xx) + cuadrado(yy)) );
printf("\nEl valor de la hipotenusa es: %f", rr);
}

La función "main", es la rutina principal de un programa en C. A partir de ella se llaman al resto de


las funciones.

Nota: Una función puede llamar a otra función. En lenguaje C existe la


recursión.

6. Apuntadores
Una variable puede ser usada por su nombre o por la dirección donde está el contenido de la
variable. ¿Cómo se pueden usar las direcciones de las variables? Bueno, mediante apuntadores.

Sintáxis:

tipo *nombre_variable;

La diferencia entre una declaración de una variable normal y un apuntador es el uso del asterisco.

Para que quede claro que es un apuntador se presenta la siguiente analogía:

15
Imagínese un libro, éste, tiene hojas y cada una de ellas está numerada. Ahora, supongamos que
tiene un índice al final del mismo y se desea hallar información relacionada con el ajedrez. Al
encontrar la palabra ajedrez en el índice se tiene el número de página; en ese momento se cae en
la cuenta de la necesidad deuna hoja para escribir esa información; enseguida se toma la hoja y se
anota la página. Acto seguido se va a la página marcada con el número encontrado y se lee la
información. En este caso el apuntador será la hoja con el número escrito en ella.

Bien, regresando al lenguaje C, cuando se declara "nombre_variable" se indica que se tiene


necesidad de un lugar donde se pueda escribir y que éste sea de tipo determinado (que en el
ejemplo precedente pudiera ser un pizarrón, una hoja, la pared, etc.). Sin embargo el objeto no
está disponible aún, por ello se requiere de una instrucción adicional que indique la acción de
tomar la hoja y tenerla dispuesta para su uso.

Un ejemplo concreto sería:

#include <stdlib.h>

char *caracter;

void main(void)
{
.
caracter = (char *)malloc(sizof(char));
.
*caracter = 'O';

La etiqueta "caracter" es el lugar en el que se puede escribir la dirección donde está la información
que requerimos, (char *) indica el tipo de variable que va a ser, es decir apuntador a char (en
nuestro ejemplo del libro: tipo hoja que tendrá números de página),mientras que "*caracter"
apunta directamente al contenido de la variable (la hoja con el número de página).

Para tomar un espacio de memoria de la computadora que sirva para fines de almacenar
direcciones se debe incluir la cabecera o "header" stdlib.h, después se declara la variable y luego se
asigna memoria mediante la función "malloc".

La función malloc asigna memoria y usa como argumento el número de bytes que se quieran usar.
Por eso se pone sizeof(char), donde la función sizeof, regresa el tamaño del tipo que se pone
como argumento. Finalmente, para que exista consistencia entre tipos, se usa el operador cast
(char *) para indicar que la variable contendrá direcciones para encontrar un char.

Si se ha definido una variable de manera "normal" (que no se haya definido como apuntador),
también se puede usar su dirección. Para ello se antepone el caracter '&' a la variable usada.

Por ejemplo:

16
float x, *y;

void main(void)
{
x = 4.3;
y = &x;
printf("El valor de y es: %f", *y);
}

El resultado del printf será que y = 4.3;

7. Compilador cc
El compilador "cc" se encuentra en todos las computadoras que tienen sistema operativo UNIX.
Por tanto es importante mencionar su existencia y su uso.

Para compilar un programa en UNIX se usa

$ cc nombre_archivo

El archivo "nombre_archivo" se denomina archivo fuente. La salida de esta instrucción va a ser un


archivo ejecutable, que por defecto tiene el nombre "a.out".

Si se desea cambiar el nombre del archivo ejecutable se puede usar la siguiente instrucción:

$ cc nombre_archivo ­o nombre_ejecutable

Este compilador puede procesar archivos fuente en ensamblador y archivos objeto.

Dependiendo de las necesidades de cada usuario podrá usar aquellas opciones que le sean más
útiles, por ejemplo, optimización en tiempo, optimización en tamaño, el tipo de arquitectura que se
está usando, etc.

En el apéndice A se presenta el manual del compilador.

8. El preprocesador de C

17
8.1. Unión de líneas
Las líneas que terminan con el carácter diagonal invertida '/' se empalman eliminando la diagonal
inversa y el carácter nueva línea.

8.2. Definición y expansión de macros


Mediante una macro se pueden definir etiquetas que van ser sustituidas en tiempo de compilación
dentro del programa.

La sintáxis es como sigue:

# define identificador secuencia­de­tokens

# define identificador (lista­de­identificadores) secuencia­de­tokens

# undef identificador

Esta última definición hace que el preprocesador olvide la definición del identificador.

Ejemplos:

#define TABSIZE 100
#define ABSDIFF(a,b)  ((a)>(b) ? (a)­(b) : (b)­(a))

En el caso del preprocesador las expresiones no terminan con punto y coma.

8.3. Inclusión de archivos


Mediante estas directivas un archivo completo se incluye en el programa actual.

# include <nombre­de­archivo> /* Pone el archivo según la ruta
indicada por el sistema */

# include "nombre­de­archivo" /* Busca el archivo en el directorio
actual, y si no lo encuentra busca 
en la ruta indicada por el sistema 
*/

# include secuencia­de­tokens /* Expande la secuencia de tokens 
como texto normal */

8.4. Compilación condicional


Estas directivas permiten tomar acciones al preprocesador en función de condiciones iniciales de
ambiente.

18
preprocesador­condicional:
línea­if texto partes­elif parte­else    #endif
opt

línea­if:

# if expresión­constante
# ifdef identificador
# ifndef identificador

partes­elif:

línea­elif texto
partes­elif (opt)

línea­elif:

# elif expresión­constante
parte­else:
# línea­else texto

línea­else:

#else

Ejemplo:

#define NUMERO 2

#ifdef NUMERO == 1
#define VAR_TOKEN  100
#define conver(x)  (x + 5)
#else
#define VAR_TOKEN  200
#define conver(x)  (x +6)
#endif

8.5. Control de línea


Ocasiona que el compilador suponga que el número de líndea de la siguiente línea fuente está dado
por la constante entera decimal y que el archivo actual de entrada está nombrado por el
identificador, todo esto par propósito de diagnóstico de errores.

# line constante "nombre­de­archivo"
# line constante

8.6. Generación de errores


Ocasiona que el preprocesador escriba un mansaje de diagnóstico que incluye
la "secuencia de tokens".

19
# error secuencia­de­tokens (opt)

8.7. Pragmas
Realiza acciones dependiendo de la implantación.

# pragma secuencia­de­tokens (opt)

8.8. Directiva nula


Una línea del preprocesador de la forma

no tiene efecto.

8.9. Nombres predefinidos


_ _LINE_ _ Constante decimal que contiene el número de línea actual.
_ _FILE_ _ Cadena literal que contiene el nombre del archivo que se está compilando.
_ _DATE_ _ Cadena literal que contiene la fecha de compilación, en la forma "Mmm dd aaaa".
_ _TIME_ _ Cadena literal que contiene la hora de la compilación, en la forma "hh:mm:ss".
_ _STDC_ _ La constante 1. Este identificador será definido como 1sólo en implantaciones que
conforman el estándar.

9. Bibliografía

Kernighan, Brian W.
Ritchie, Dennis M.
El lenguaje de programación C
Prentice Hall.
1991. Segunda edición

Barkakati, Naba
The Waite Group’s Turbo C++ Bible
SAMS.
1990.

20
Apéndice A Compilador XL C

Compilador XL C Versión 1.3.0.0

USO:

cc [ opcion | archivo ]

DESCRIPCIÓN:
Estos comandos también procesan archivos fuente en ensamblador y archivos objeto. A menos de
que se especifique la opción -c, estos comandos llaman al editor de liga para producir un archivo
objeto sencillo. Los archivos de entrada pueden ser de la siguiente manera:

1. nombre del archivo con extensión .c: archivo fuente en C


2. nombre del archivo con extensión .i: archivo preprocesado fuente en C
3. nombre del archivo con extensión .o: archivo objeto para el comando ld
4. nombre del archivo con extensión .s: archivo fuente en ensamblador

OPCIONES:
Las opciones pueden ser una o más de las siguientes:

1.Opciones Bandera:

-# Despliega información adicional sobre el progreso de compilación sin invocar nada.


-B<prefijo> Construye nombres de programas para el editor de ligas, ensamblador y
compilador. El <prefijo> es añadido al inicio del nombre estándar de los nombres
de programas.
-c Compila solamente; no llama al comando ld.
-C Escribe comentarios a la salida mientras se realiza el preprocesamiento usado con
-E y -P.
-D<nombre>[=<def>]
Define <nombre> como en la directiva #define. Si <def> no se especifica, se asume
como 1.
-E Preprocesa pero no compila; las salidas van a la consola.
-F<x>[:<stanza>]
Usa una configuración alterna del archivo <x> dejando opcional <stanza>. Si no se
especifica el <stanza>, se asume como xlc.

21
-g Produce información de depuración.
-I<dir> Busca en el directorio <dir> archivos incluidos que no comienzen con una ruta
absoluta.
-l<key> Busca el archivo de librería específico, donde <key> selecciona el archivo
lib<key>.a.
-L<dir> Busca en el directorio <dir> archivos especificados por -l<key>.
-M Crea un archivo de salida compatible para la inclusión en un archivo de descripción
para el comando make en UNIX.
-o<nombre> Cuando se usa con -C, nombra el archivo <nombre>.o, de otra forma, nombra el
archivo ejecutable <nombre> en vez de a.out.
-O Optimiza el código generado.
-O2 Nivel equivalente de optimización como -O en la versión anterior.
-O3 Realiza la optimización en el uso de memoria y tiempo de compilación además de
aquellos ejecutados con -O2. Las optimizaciones específicas de -O3 tienen el
potencial para alterar las semánticas del programa del usuario.
-p Genera un código simple de soporte.
-pg Genera un código más extenso de soporte que -p.
-P Preprocesado pero no compila; su salida genera un archivo con extensión .i.
-Q<x> Enlínea todas las funciones apropiadas donde x puede ser una de las siguientes:
! No enlínea función alguna.
=<lc> Enlínea si el número de la sentencia fuente en la función es menor que el
especificado en <lc>.
-<nm> Función no enlineada listada por nombres en <nm>.
+<nm> Enlínea la función listada por nombres en <nm>.
-S Produce un archivo con extensión .s para cualquier archivo fuente procesado por el
compilador.
-t<x> Utiliza el prefijo de la opción -B al programa <x> especificado, donde x puede ser
uno o más de las siguientes:
p = preprocesador
c = compilador
a = ensamblador
l = editor de ligas.
-U<nombre> Nombre indefinido como en la directiva #undef.
-v Despliega información adicional en el progreso de compilación.
-w Suprime información, nivel del lenguaje y mensajes de advertencia.
-y<x> Especifica el tiempo de compilación de las expresiones de punto flotante
constantes, donde <x> puede ser una de las siguientes:
n = redondeando al valor más cercano
m = acercándose a menos infinito
p = acercándose a más infinito
z = redondeando a cero.

2. Otras Opciones:

Otras opciones se especifican como sigue:

-q<opción>

22
donde <opción> es un switch on/off de manera que, si x es la opción, -qx cambia la opción a on, y
-qnox cambia la la opción a off. Por ejemplo, -qsource le dice al compilador que produzca un
listado fuente, y -qnosource le dice al compilador que no produzca un listado fuente.

Las opciones son las siguientes:

ansialias Especifica el tipo de base de denominación que será usado durante la optimización.
attr Produce un listado de atributos (solamente los referenciados).
compact Reduce el tamaño del código donde sea posible, dependiendo de la velocidad de
ejecución. El tamaño del código es reducido por optimizaciones inhibidas que
expanden el código entre líneas.
cpluscmt Permite a "//" introducir un comentario que se mantiene hasta el final de la linea
fuente actual, como en C++.
dbxextra Genera una tabla de información de símbolos para variables no referenciadas. Por
defecto dicha información no se genera a menos que se reduzca la compilación
ejecutable con la opción -g.
extchk Realiza externamente el chequeo de los nombres y funciones.
idirfirs Especifica el orden de búsqueda para archivos incluidos con la directiva #include
"nombre_archivo". Usar -qidirfirst con la opción -Idirectorio. Si la opción -qidirfirst
es especificada, los directorios especifica dos por la opción son buscados antes del
directorio donde se encuentra el archivo actual se encuentra.
inlglue Genera rápidamente la liga externa enlineando el código necesario con llamadas por
un apuntador de función y llamadas a procedimientos externos.
list Produce un listado objeto.
listopt Imprime marcas de todas las opciones en el listado.
mbcs Los strings literales y los comentarios pueden
contener caracteres MBCS.
noprint Direcciona el listado a /dev/null.
nostdinc Especifica que archivos estan incluidos con las directivas #include
"nombre_archivo" y #include <nombre_arch> Si -qnostdinc es especificado, el
directorio/usr/include no es buscado.
ro No pone las literales de la cadena en el área de sólo lectura
phsinfo Despliega información de fase en la pantalla.
ro Establece las cadenas literales en el área de sólo lectura. Esta opción está por
defecto para xlc.
roconst Establece identificadores estáticos externos y globales que son constantes
calificadas en el área de sólo lectura.
source Produce el listado fuente.
srcmsg Especifica que las líneas fuente a ser desplegadas con el mensaje con apuntadores a
la posición de la columna del error.
statsym Agrega nombres no externos definidos por el usuario que tienen como clase
almacenamiento estático al nombre de la lista.
strict Válido únicamente en -O3. Esta opción cambia a off la optimización agresiva que
tiene el potencial para alterar las semánticas del programa del usuario. Esta opción
también establece -qfloat=nofltint:norsqrt.
tocdata Establece los datos escalares externos de una palabrao menos en la tabla de
contenidos (TOC). Si se activa esta opción, la dirección del dato escalar externo se

23
establece en el TOC. Esto requiere una llamada extra de la dirección antes de
accesar el dato.
xcall Genera el código de rutinas estáticas sin una unidad de compilación como si fueran
rutinas externas.
xref Produce un listado de referencia cruzada (sólo nombres referenciados).

-q<opción>=<subopción>
-q<opción>=<subopción1>:<subopción2>:...:<subopciónN>

donde <opción> se le asigna un valor de subopción específica o una lista de valores de subopción
como sigue:

align=<algnopt>

Especificar una de las siguientes tres reglas de alineamiento:


- arquitectura POWER (align=power, default)
- alineación de dos bytes (align=twobyte)
- alineación de un byte (align=packed)
arch=<opción>

Especifica la arquitectura donde el programa ejecutable correrá. Las opciones disponibles son:

com Produce un objeto que contiene instrucciones que correrán en toda plataforma de
hardware POWER y PowerPC.
pwr Produce un objeto que contiene instrucciones que correrán en la plataforma de
hardware POWER.
pwr2 Produce un objeto que contiene instrucciones que correrán en la plataforma de
hardware POWER2
pwrx Lo mismo que pwr2.
ppc Produce un objeto que contiene instrucciones que correrán en cualquier plataforma
de harware de 32-bits y PowerPC. Si la opción -qarch es especificada sin el -qtune=
<opción>, el compilador usará -qtune=pwr.
attr=full Produce una lista de atributos (todos los nombres, referenciados o no).
chars=signed El tipo de dato char será señalado.
datalocal=<nombre1>:<nombre2>:
Especifica qué datos son locales. Si no hay nombres especificados, todos se
asumirán como locales.
dataimported=<nombre1>:<nombre2>:
Especifica qué datos son importados. Si no hay nombres especificados, todos se asumirán como
importados. Esto esta por default.
enum=<enumopt>
Especifica si los tipos enumerados de tamaño mínimo serán producidos o no.<enumopt> puede ser
small o int. Small denota que uno, dos o cuatro bytes de almacenamiento serán
establecidos para enum variables basadas en el rango de las constantes enum. Int
esta por default, y causa que las enum variables sean tratadas como si fueran de
tipo señalado int.
flag=<sev1>:<sev2>

24
Especifica el nivel de severidad de los diagnósticos que serán reportados en listados, <sev1>, y en
la pantalla, <sev2>.

float=<opt1>:<opt2>:...:<optN>

Las opciones disponibles son:

hssngl Redondea las expresiones de precisión sencilla sólo cuando los resultados son
almacenados en las localidades de memoria REAL*4.
nans Detecta la conversión de NaNS de precisión sencilla con precisión doble llamando a
chequeo.
hsflt Nunca redondea expresiones de precisión sencilla, y no realiza el chequeo de rango
de punto flotante para integrar conversiones.
nomaf Suprime la generación de instrucciones suma-multiplicación.
nofold Suprime la evaluación de tiempo-compilación de las expresiones constantes de
punto flotante.
rrm Especifica el modo de tiempo-corrida. Compilar con esta opción si este modo se
redondea a menos infinito, a más infinito o no se conoce.
rsqrt Especifica si la división del resultado de una raiz cuadrada puede ser reemplazado
con un multiplicador por el recíproco de la raiz cuadrada. Por omisión a -O2:
-qfloat=norsqrt. Por omisión a -O3: -qfloat=rsqrt.
fltint Especifica si el rango checado del punto flotante para integrar conversiones esta
hecho. Por omisión a -O2: -qfloat=nofltint. Por omisión a -O3: -qfloat=fltint.
flttrap=<opt1>:<opt2>:...:<optN> Genera instrucciones para detectar el punto flotante.Las
opciones disponibles son: overflow, underflow, zerodivide, invalid, inexact, enable,
imprecise.
halt=<sev> Detiene el compilador después de la primera fase si la severidad de los errores
detectados es igual o equivale a <sev>.
initauto=<hh> Inicializa el almacenamiento automático a <hh>. <hh> es un valor hexadecimal.
Esto genera un código extra y sólo deberá ser usado para la determicación de error.
isolated_call=<nombre1>:<nombre2>:
Especifica que los llamados a las funciones listadas no tienen efectos secundarios.
<nombre1> y <nombre2> son nombres de función. El usuario especificará los
nombres de función como sea necesario.
langlvl=<langlvl>
Especifica el nivel del lenguaje que será utilizado durante la compilación. <langlvl>
puede ser ansi, saal2, saa, o extendido.
maxmem=<num>
Limita la cantidad de memoria utilizado por las optimizaciones de espacio
intensivas a <num>. <num> esta especificado en kilobytes.
pgmsize=<p> Establece el tamaño de la tabla de inicio que será usada por el compilador. <p>
puede ser s, para pequeño; o l para largo.

proclocal=<nombre1>:<nombre2>: ...

25
Especifica qué funciones son locales. Si no se especifican los nombres, todas las
funciones invocadas se asumen que estan definidas dentro del archivo en uso. Las
últimas especificaciones explícitas para una función toman precedencia.
procimported=<nombre1>:<nombre2>: ...
Especifica qué funciones son importadas. Si los nombres de archivo no son
especificados, todas las funciones invocadas se asumen que estan definidas fuera
del archivo en uso. Las últimas especificaciones explicitas para una función toman
precedencia.
procunknown=<nombre1>:<nombre2>: ...
Especifica qué funciones no se conocen como locales o importadas. Si no son
especificados los nombres de los archivos, todas las llamadas a funciones se asumen
como desconocidas. Este es el default cuando el usuario no especifica opciones.
Las últimas especificaciones explicitas para una función toman precedencia.
spill=<tamaño>
Especifica el tamaño del area de localización del registro.
tune=<opción>
Especifica el sistema de arquitectura para la que el programa ejecutable es óptimo.
Las opciones disponibles son:
601 Produce un objeto optimizado para todos los procesadores PowerPC601 .
pwr Produce un objeto optimizado para la plataforma de hardware POWER.
pwr2 Produce un objeto optimizado para la plataforma de hardware POWER2.
pwrx Lo mismo que pwr2.
xref=full Produce un listado de referencia cruzada (todos los nombres referenciados o no).

26