Software">
Gccintro Es
Gccintro Es
Gccintro Es
Brian Gough
Prefacio por Richard M. Stallman
El registro de este libro está disponible en la Biblioteca Británica.
ISBN 0-9541617-9-3
Índice General
Prefacio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1 Una breve historia de GCC . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Importantes caracterı́sticas de GCC. . . . . . . . . . . . . . . . . . . . 6
1.3 Programación en C y C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.4 Convenciones usadas en este manual . . . . . . . . . . . . . . . . . . . 7
2 Compilando un programa C . . . . . . . . . . . . 9
2.1 Compilando un peque~ no programa C . . . . . . . . . . . . . . . . . . 9
2.2 Encontrando errores en un peque~ no programa. . . . . . . . . 10
2.3 Compilando múltiples archivos fuentes . . . . . . . . . . . . . . . . 11
2.4 Compilando archivos independientes . . . . . . . . . . . . . . . . . . 13
2.4.1 Creando archivos objeto desde archivos fuente . . . 13
2.4.2 Creando ejecutables desde archivos objeto . . . . . . . 14
2.5 Recompilando y reenlazando. . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.6 Un peque~no makefile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.7 Enlazando con librerı́as externas . . . . . . . . . . . . . . . . . . . . . . 18
2.7.1 Orden de enlace de librerı́as . . . . . . . . . . . . . . . . . . . . . 20
2.8 Usando librerı́as de archivos de cabeceras . . . . . . . . . . . . . 21
3 Opciones de compilación . . . . . . . . . . . . . . . 23
3.1 Asignando rutas de búsqueda . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.1.1 Ejemplo de ruta de búsqueda . . . . . . . . . . . . . . . . . . . . 24
3.1.2 Variables de entorno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.3 Rutas de búsqueda extendidas . . . . . . . . . . . . . . . . . . . 27
3.2 Librerı́as compartidas y librerı́as estáticas . . . . . . . . . . . . . 28
3.3 Estándares del lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3.1 ANSI/ISO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3.2 ANSI/ISO estricto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.3 Seleccionando estándares especı́ficos . . . . . . . . . . . . . 34
3.4 Opciones de aviso en -Wall. . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.5 Opciones de aviso adicionales . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.6 Opciones de aviso recomendadas . . . . . . . . . . . . . . . . . . . . . . 41
ii Una Introducción a GCC
4 Usando el preprocesador . . . . . . . . . . . . . . . 43
4.1 Definiendo macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.2 Macros con valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.3 Preprocesando archivos fuentes . . . . . . . . . . . . . . . . . . . . . . . 46
9 Resolución de problemas . . . . . . . . . . . . . . . 91
9.1 Opciones de ayuda en lı́nea de comandos . . . . . . . . . . . . . 91
9.2 Números de versión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
9.3 Compilación verbosa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
9.4 Parando un programa en un bucle infinito . . . . . . . . . . . . 95
9.5 Previniendo un uso excesivo de memoria . . . . . . . . . . . . . . 97
Reconocimientos . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Índice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Una Introducción a GCC 1
Prefacio
Este Prefacio es una amable contribución de Richard M. Stallman,
el principal autor de GCC y fundador del Proyecto GNU.
Este libro es una guı́a para iniciarse en GCC, GNU Compiler
Collection (Colección de Compiladores GNU). Se mostrará cómo
usar GCC como una herramienta de programación. GCC es una
herramienta de programación, esto es verdad— pero también es
algo más. También forma parte de la campa~ na por la libertad de
los usuarios de ordenadores desde hace más de 20 a~ nos.
Todo lo que queremos es buen software, pero ¿qué significa para
nosotros que un software sea bueno?. Funcionalidades adecuadas
y fiabilidad puede ser algo técnicamente bueno, pero esto no es
suficiente. Un buen software debe además ser éticamente bueno:
tiene que ser respetuoso con la libertad de los usuarios.
Como usuario de software, se deberı́a tener el derecho a ejecu-
tarlo como se necesite, el derecho a estudiar el código fuente y a
cambiarlo como se desee, el derecho a redistribuir copias de éste
a terceras personas, y el derecho a publicar versiones modificadas
con lo que se puede contribuir a la construcción de la comunidad.
Cuando un programa respeta la libertad de esta forma, se dice que
es software libre. Anteriormente a GCC habı́a otros compiladores
para C, Fortran, Ada, etc. Pero no eran software libre, y no se
podı́an usar libremente. Escribı́ el GCC para que se pueda usar un
compilador sin perder nuestra libertad.
Un compilador solo no es suficiente —para usar un sistema de
computación, se debe disponer de un sistema operativo completo.
En 1983, todos los sistemas operativos para ordenadores modernos
eran no libres. Para remediar esto, en 1984 comencé a desarrollar
el sistema operativo GNU, un sistema similiar a Unix que serı́a
software libre. El desarrollo de GCC fué una parte del desarrollo
de GNU.
A principios de los 90, el recién terminado sistema operativo
GNU fué completado con la suma de un kernel, Linux, que se hizo
software libre en 1992. El sistema operativo combinado GNU/Linux
ha alcanzado la meta de hacer posible el uso de una computadora en
libertad. Pero la libertad nunca está automáticamente asegurada,
y debemos trabajar para protegerla. El Movimiento del Software
Libre necesita tu apoyo.
Richard M. Stallman
Febrero de 2004
Capı́tulo 1: Introducción 5
1 Introducción
El propósito de este libro es explicar el uso de los compiladores
de GNU C y C++, gcc y g++. Después de leer este libro se com-
prenderá como compilar un programa y, cómo usar las opciones
básicas del compilador para optimización y depuración. Este libro
no intenta ense~nar los lenguajes C o C++ en sı́, este material puede
ser encontrado en muchos otros lugares (véase [Lectura adicional],
página 131).
Los programadores experimentados que están familiarizados con
otros sistemas, pero son nuevos en compiladores GNU, pueden
saltarse las primeras secciones de los capı́tulos “Compilando un pro-
grama C”, “Usando el preprocesador” y “Compilando un programa
C++”. Las secciones y capı́tulos restantes proporcionan una buena
visión del conjunto de las funcionalidades de GCC para aquellos
que ya saben cómo usar otros compiladores.
2
Ver http://www.network-theory.co.uk/gcc/intro/
Capı́tulo 2: Compilando un programa C 9
2 Compilando un programa C
Este capı́tulo describe cómo compilar programas C usando gcc.
Los programas pueden ser compilados desde un solo fichero fuente
o desde múltiples ficheros fuente, y pueden usar librerı́as de sistema
y ficheros de cabecera.
La compilación se refiere al proceso de convertir un programa
desde el código fuente textual de un lenguaje de programación tal
como C o C++, en código máquina, la secuencia de unos y ceros
usados para controlar la unidad central de proceso (CPU) del orde-
nador. Este código máquina es almacenado en un fichero conocido
como fichero ejecutable, a veces también llamado fichero binario.
int
main (void)
{
printf ("!Hola, mundo!\n");
return 0;
}
Se asume que el código fuente está almacenado en un fichero lla-
mado ‘hola.es.c’. Para compilar el fichero ‘hola.es.c’ con gcc,
se puede usar el siguiente comando:
$ gcc -Wall hola.es.c -o hola
Esto compila el código fuente de ‘hola.es.c’ a código máquina y lo
almacena en el fichero ejecutable ‘hola’. El fichero de salida para
el código máquina se especifica usando la opción ‘-o’. Esta opción
normalmente es el último argumento en la lı́nea de comandos. Si se
omite, la salida es escrita a un fichero por defecto llamado ‘a.out’.
Nótese que si ya existe un fichero con el mismo nombre que el
fichero ejecutable en el directorio actual, entonces se sobreescribirá.
La opción ‘-Wall’ activa todos los avisos más comunes —¡se re-
comienda usar siempre esta opción!. Hay muchas otras opciones de
avisos que serán discutidas en capı́tulos posteriores, pero ‘-Wall’
es la más importante. GCC no producirá avisos a menos que estén
activados. Los avisos del compilador son una ayuda esencial de-
tectando problemas al programar en C y C++.
10 Una Introducción a GCC
int
main (void)
{
printf ("Dos y dos son %f\n", 4);
return 0;
}
Este error no es obvio a primera vista, pero puede ser detectado
por el compilador si la opción de aviso ‘-Wall’ se ha habilitado.
Al compilar el anterior programa, ‘mal.es.c’, con la opción
‘-Wall’ produce el siguiente mensaje:
$ gcc -Wall bad.c -o bad
bad.c: In function ’main’:
bad.c:6:3: warning: format ’%f’ expects argument of
type ’double’, but argument 2 has type ’int’ [-Wformat]
Esto indica que un formato de cadena ha sido usado incorrec-
tamente en el fichero ‘mal.es.c’ en la lı́nea 6. Los mensajes
producidos por GCC siempre tienen la forma fichero:número de
lı́nea:mensaje. El compilador distingue entre mensajes de error,
que impiden una compilación exitosa, y mensajes de aviso que in-
dican posibles problemas (pero no detienen la compilación).
Capı́tulo 2: Compilando un programa C 11
int
main (void)
{
hola ("mundo");
return 0;
}
12 Una Introducción a GCC
void
hola (const char * nombre)
{
printf ("!Hola, %s!\n", nombre);
}
Esta función imprime el mensaje “¡Hola, nombre !” usando como
valor de nombre el argumento introducido.
Casualmente, la diferencia entre las dos formas de la instrucción
de inclusión #include "FILE.h" y #include <FILE.h> es que la
primera busca el archivo ‘FILE.h’ en el directorio actual antes de
buscarlo en los directorios de los archivos de cabeceras del sistema.
La instrucción de inclusión #include <FILE.h> busca por defecto
los archivos de cabeceras del sistema, pero no busca en el directorio
actual.
Para compilar estos ficheros fuente con gcc, se usa el siguiente
comando:
$ gcc -Wall main.es.c hola_fn.es.c -o nuevohola
En este caso, se usa la opción ‘-o’ para especificar un nombre al
fichero de salida diferente para el ejecutable, ‘nuevohola’. Nótese
que el fichero de cabecera ‘hola.es.h’ no está especificado en la
lista de ficheros en la lı́nea de comandos. La directiva #include
Capı́tulo 2: Compilando un programa C 13
int
main (void)
{
hola ("cualquiera"); /* se cambia "mundo" */
return 0;
}
El fichero actualizado ‘main.es.c’ ahora puede ser recompilado con
el siguiente comando:
$ gcc -Wall -c main2.es.c
Esto produce un nuevo fichero objeto ‘main.o’. No se necesita
crear un nuevo fichero objeto para ‘hola_fn.es.c’, debido a que el
fichero y los
ficheros relacionados de los que depende, tales como ficheros de
cabeceras, no han cambiado.
El nuevo fichero objeto puede ser reenlazado con la función hola
para crear un nuevo fichero ejecutable:
$ gcc main2.es.o hola_fn.o -o hola
El ejecutable resultante ‘hola’ ahora usa la nueva función main para
producir la siguiente salida:
$ ./hola
¡Hola, cualquiera!
Nótese que solo el fichero ‘main.es.c’ ha sido recompilado y, por
tanto, reenlazado con el fichero objeto existente para la función
hola. Si el fichero ‘hola_fn.es.c’ hubiera sido modificado, se
podrı́a haber recompilado ‘hola_fn.es.c’ para crear un nuevo
fichero objeto ‘hola_fn.o’ y reenlazar este con el fichero ‘main.o’.1
En un gran proyecto con muchos ficheros fuente, recompilar solo
aquellos que han sido modificados crea un significativo ahorro. El
proceso de recompilar solo los ficheros modificados en un proyecto
puede ser automatizado con el programa estándar de Unix make.
1
Si el prototipo de una función cambia, es necesario modificar y recompilar
todos los ficheros fuentes que la usan.
16 Una Introducción a GCC
2.6 Un peque~
no makefile
Para aquellos no familiarizados con make, esta sección provee una
demostración de su uso. make es un programa propio que puede ser
encontrado en todos los sistemas Unix. Para aprender más acerca
de la versión GNU de make se necesitará consultar el manual de
GNU Make escrito por Richard M. Stallman y Roland McGrath
(véase [Lectura adicional], página 131).
make lee una descripción de un proyecto desde un archivo cono-
cido por makefile (por defecto, llamado ‘Makefile’ en el directorio
actual). Un makefile especifica un conjunto de reglas de compilación
en términos de objetivos (tal como ejecutables) y sus dependencias
(tal como ficheros objeto y ficheros fuente) en el siguiente formato:
objetivo: dependencias
comando
Por cada objetivo, make chequea el momento de modificación de los
correspondientes ficheros de dependencia para determinar si el ob-
jetivo necesita ser reconstruido usando el correspondiente comando.
Nótese que las lı́neas de comandos en un makefile deben ser inden-
tadas con un carácter TAB, sin espacios.
GNU Make contiene muchas reglas por defecto, llamadas reglas
implı́citas, para simplificar la construcción de makefiles. Por ejem-
plo, estos especifican que ficheros ‘.o’ pueden ser obtenidos desde
ficheros ‘.c’ al compilarse, y que un ejecutable puede ser creado
enlazando ficheros ‘.o’ juntos. Las reglas implı́citas son definidas
en términos de variables make, tales como CC (el compilador de
C) y CFLAGS (las opciones de compilación para programas C), que
pueden ser asignadas usando lı́neas VARIABLE=VALUE en el makefile.
Para C++ las variables equivalentes son CXX y CXXFLAGS, mientras
la variable CPPFLAGS asigna las opciones del preprocesador. Las re-
glas implı́citas y las definidas por el usuario se encadenadan juntas
de forma automática como GNU Make necesite.
Un ‘Makefile’ simple para el proyecto anterior puede ser escrito
como sigue:
CC=gcc
CFLAGS=-Wall
main: main.o hello_fn.o
clean:
rm -f main main.o hello_fn.o
El fichero puede ser leido de la manera siguiente: usando el com-
pilador de C gcc, con la opción de compilación ‘-Wall’, se con-
struirá el objetivo ejecutable main desde los ficheros objeto ‘main.o’
Capı́tulo 2: Compilando un programa C 17
int
main (void)
{
double x = 2.0;
double y = sqrt (x);
printf ("La raiz cuadrada de %f es %f\n", x, y);
3
En sistemas que soportan versiones de librerı́as ejecutables de 32 y 64 bits,
las versiones de 64 bit se almacenarán frecuentemente en ‘/usr/lib64’ y
‘/lib64’, y las versiones de 32 bits en ‘/usr/lib’ y ‘lib’.
Capı́tulo 2: Compilando un programa C 19
return 0;
}
Intentar crear un ejecutable desde este único fichero fuente causa
que el compilador devuelva un error en la fase de enlace:
$ gcc -Wall calc.es.c -o calc
/tmp/ccbR6Ojm.o: In function ‘main’:
/tmp/ccbR6Ojm.o(.text+0x19): undefined reference
to ‘sqrt’
El problema es que la referencia a la función sqrt no puede ser
resuelta sin la librerı́a matemática externa ‘libm.a’. La función
sqrt no está definida en el programa o en la librerı́a por defecto
‘libc.a’, y el compilador no enlaza al fichero ‘libm.a’ a menos
que éste esté explı́citamente seleccionado. Casualmente, el fichero
mencionado el mensaje de error ‘/tmp/ccbR60jm.o’ es un fichero
objeto temporal creado por el compilador desde ‘calc.es.c’, para
llevar a cabo el proceso de enlace.
Para permitir que el compilador enlace la función sqrt al pro-
grama main de ‘calc.es.c’ es necesario proveer la librerı́a ‘libm.a’.
Un obvio pero no convencional modo de hacer esto es especificarlo
de manera explı́cita en la lı́nea de comandos:
$ gcc -Wall calc.es.c /usr/lib/libm.a -o calc
La librerı́a ‘libm.a’ contiene los ficheros objeto para todas las fun-
ciones matemáticas, tales como sin, cos, exp, log y sqrt. El
enlazador busca a través de estos para encontrar el fichero objeto
conteniendo la función sqrt.
Una vez que el fichero objeto para la función sqrt fué encon-
trado, el programa main puede ser enlazado y se produce un eje-
cutable completo:
$ ./calc
La raı́z cuadrada de 2.000000 es 1.414214
El fichero ejecutable incluye el código máquina para la función main
y el código máquina para la función sqrt, copiado desde el archivo
objeto correspondiente en la librerı́a ‘libm.a’.
Para evitar la necesidad de especificar largas rutas en la lı́nea
de comandos, el compilador proporciona una opción de atajo ‘-l’
para enlazar librerı́as. Por ejemplo, el siguiente comando,
$ gcc -Wall calc.es.c -lm -o calc
es equivalente al comando original usando el nombre de la librerı́a
completa ‘/usr/lib/libm.a’.
20 Una Introducción a GCC
int
main (void)
{
double x = strtod ("123", NULL);
printf ("El valor es %f\n", x);
return 0;
}
Sin embargo, el programa contiene un error —la sentencia
#include para la necesaria cabecera ‘stdlib.h’ no se encuentra,
ası́ el prototipo double strtod (const char * string, char *
tail) no será visto por el compilador.
La compilación del programa sin opciones de aviso producirá un
fichero ejecutable que da resultados incorrectos:
$ gcc badconv.es.c -lm
$ ./a.out
El valor es 966656.000000 (resultado incorrecto,
deberı́a ser 123.0)
Los resultados están corruptos porque los argumento y el valor de-
vuelto de la llamada a strtod son pasados con tipos incorrectos.4
Esto puede ser detectado activando la opción de avisos ‘-Wall’:
4
La actual salida anterior puede diferir, dependiendo de la plataforma y el
entorno especı́ficos.
22 Una Introducción a GCC
3 Opciones de compilación
Este capı́tulo describe otras opciones del compilador comúnmente
usadas disponibles en GCC. Estas opciones controlan funcionali-
dades tales como buscar rutas usadas para localizar librerı́as e in-
cluir ficheros, el uso de avisos adicionales y diagnósticos, macros del
preprocesador y dialectos del lenguaje C.
int
main (void)
{
GDBM_FILE dbf;
datum key = { "clavetest", 7 }; /* clave, tamano */
datum value = { "valortest", 9 }; /* valor, tamano */
3.3.1 ANSI/ISO
A veces un programa ANSI/ISO puede ser incompatible con las ex-
tensiones de GNU C. Para tratar con esta situación, la opción del
compilador ‘-ansi’ inhabilita las extensiones de que están en con-
flicto con el estándar ANSI/ISO. Los sistemas que usan la GNU
C Library (glibc) también deshabilitan las extensiones a la li-
brerı́a estándar de C. Esto permite que los programas escritos para
ANSI/ISO sean compilados sin efectos no deseados de extensiones
de GNU.
Por ejemplo, aquı́ hay un programa ANSI/ISO C válido que usa
una variable llamada asm:
#include <stdio.h>
int
main (void)
{
const char asm[] = "6502";
printf ("la cadena asm es ’%s’\n", asm);
return 0;
}
El nombre de variable asm es válido bajo el estándar ANSI/ISO,
pero este programa no compilará en GNU C porque asm es una
palabra reservada de la extensión GNU C (permite instrucciones
32 Una Introducción a GCC
int
main (void)
{
printf ("el valor de pi es %f\n", M_PI);
return 0;
}
La constante M_PI no es parte de la librerı́a estándar ANSI/ISO de
C (viene de la versión BSD de Unix). En este caso, el programa no
compilará con la opción ‘-ansi’:
$ gcc -Wall -ansi pi.c
pi.c: In function ’main’:
pi.c:7:38: error: ’M_PI’ undeclared (first use in this
function)
pi.c:7:38: note: each undeclared identifier is reported
only once for each function it appears in
El programa puede ser compilado sin la opción ‘-ansi’. En este caso
tanto el lenguaje como las extensiones de librerı́a están habilitadas
por defecto:
Capıtulo 3: Opciones de compilacion 33
return 0;
}
Este programa compilará con la opción ‘-ansi’, porque soporta
arrays de tama~ no variable que no interfieren con la compilación de
programas ANSI/ISO válidos —ésta es una extensión compatible
hacia atrás:
$ gcc -Wall -ansi gnuarray.es.c
Sin embargo, compilar con ‘-ansi -pedantic’ devuelve avisos de
las violaciones del estándar ANSI/ISO:
$ gcc -Wall -ansi -pedantic gnuarray.es.c
gnuarray.es.c: In function ‘main’:
gnuarray.es.c:5: warning: ISO C90 forbids variable-size
array ‘x’
Nótese que una ausencia de avisos con ‘-ansi -pedantic’ no
garantiza que un programa cumpla estrictamente con el estándar
ANSI/ISO. El estándar en sı́ especifica sólo un limitado conjunto
de circunstancias que deberı́an generar diagnósticos, y estos son los
que se informa con ‘-ansi -pedantic’.
/* comentario exterior */
#if 0
double x = 1.23 ; /* posición x */
#endif
‘-Wformat’ (incluida en ‘-Wall’)
Esta opción avisa acerca del incorrecto uso del formato
de cadenas en funciones tales como printf y scanf,
donde el especificador de formato no concuerda con el
tipo del correspondiente argumento de la función.
‘-Wunused’ (incluida en ‘-Wall’)
Esta opción avisa acerca de variables no usadas.
Cuando una variable es declarada pero no se usa, puede
ser debido a que otra variable ha sido accidentalmente
sustituida en su lugar. Si la variable realmente no se
necesita, ésta pueder ser eliminada del código fuente.
‘-Wimplicit’ (incluida en ‘-Wall’)
Esta opción avisa de cualquier función que es usada sin
haber sido declarada. La razón más común para que
una función sea usada sin haber sido declarada es haber
olvidado incluir un fichero de cabecera.
36 Una Introducción a GCC
int
main (void)
{
printf ("hola mundo\n");
return;
}
La falta de un valor de retorno en el código de arriba
podrı́a ser el resultado de una omisión accidental por
el programador —el valor devuelto por la función main
es el valor de retorno de la función printf (el número
de caracteres impresos). Para evitar ambiguedad, es
preferible usar un valor explı́cito en la sentencia de re-
torno, bien una variable, ó bien una constante, como
return 0.
El conjunto completo de opciones de aviso incluidas en ‘-Wall’
puede encontrarse en el Manual de Referencia de GCC “Using
GCC” (véase [Lectura adicional], página 131). Las opciones in-
cluidas en ‘-Wall’ tienen la caracterı́stica común de informar de
construcciones son siempre erróneas, o pueden ser fácilmente ree-
scritas en un inambiguo camino correcto. Esta es la razón de que
éstos sean tan útiles —cualquier aviso producido por ‘-Wall’ puede
ser tomado como una indicación de un potencial serio problema.
Capı́tulo 3: Opciones de compilación 37
‘-Wconversion’
Esta opción avisa acerca de conversiones implı́citas de
tipo que podrı́an causar resultados inesperados, tales
como conversiones entre tipos reales y enteros, entre
tipos con y sin signo y entre tipos de diferente tama~no
(por ej. enteros long y short). Las conversiones pueden
ocurrir en expresiones y asignaciones, y en llamadas a
funciones si los tipos de los argumentos no concuerdan
con aquellos especificados en el prototipo.
Por ejemplo, el valor entero de la función absoluto int
abs(int i) es fácilmente confundido con la correspon-
diente función de coma flotante double fabs(double
x). Esto puede traer resultados incorrectos, como
muestra el siguiente programa:
#include <stdio.h>
#include <stdlib.h>
int
main (void)
{
double x = -3.14;
double y = abs(x); /* debe ser fabs(x) */
printf ("x = %g |x| = %g\n", x, y);
return 0;
}
Tras compilar esta función con ‘-Wall’ no se produce
ningún aviso,
$ gcc -Wall wabs.es.c
$ ./a.out
x = -3.14 |x| = 3 (incorrecto)
pero da un aviso con ‘-Wconversion’:
$ gcc -Wall -Wconversion wabs.c
wabs.c: In function ’main’:
wabs.c:8:3: warning: conversion to ’int’ from
’double’ may alter its value [-Wconversion]
La opción ‘-Wconversion’ también captura errores
tales como la asignación de un valor negativo a una
variable sin signo, como en el siguiente código,
Capıtulo 3: Opciones de compilacion 39
4 Usando el preprocesador
Este capı́tulo describe el uso del preprocesador C GNU cpp, que
forma parte del paquete GCC. Este preprocesador expande las
macros en los ficheros fuentes antes de ser compilados. Es invo-
cado de forma automática cada vez que GCC procesa un programa
C o C++.1
int
main (void)
{
#ifdef TEST
printf ("Modo test\n");
#endif
printf ("Ejecutando...\n");
return 0;
}
Cuando la macro está definida, el preprocesador incluye el código
correspondiente antes del comando de cierre #endif. En este ejem-
plo la macro comprobada es llamada TEST, y la parte condicional
del código fuente es la instrucción printf que imprime el mensaje
“Modo test”.
La opción de gcc ‘-DNAME’ define una macro del preprocesador
NAME desde la lı́nea de comandos. Si el programa anterior es com-
pilado con la opción de lı́nea de comandos ‘-DTEST’, la macro TEST
será definida y el ejecutable resultante imprimirá ambos mensajes:
int
main (void)
{
printf ("El valor de NUM es %d\n", NUM);
return 0;
}
Capı́tulo 4: Usando el preprocesador 45
int
main (void)
{
printf ("El valor de NUM es %d\n", 2+2);
return 0;
}
Observe que una buena idea es encerrar las macros entre paréntesis
siempre que formen parte de una expresión. Por ejemplo, el pro-
grama siguiente usa paréntesis para asegurar la correcta precedencia
para la multiplicación 10*NUM:
#include <stdio.h>
int
main (void)
{
printf ("Diez veces NUM es %d\n", 10 * (NUM));
return 0;
}
Con estos paréntesis, se produce el resultado esperado cuando se
compila con la misma lı́nea de comandos anterior:
46 Una Introducción a GCC
int
main (void)
{
printf ("!Hola, mundo!\n");
return 0;
}
Es posible examinar las declaraciones incluidas en los archivos de
cabeceras preprocesando el archivo con gcc -E:
$ gcc -E hola.es.c
En un sistema GNU, esto produce una salida similar a lo siguiente:
# 1 "hola.es.c"
# 1 "/usr/include/stdio.h" 1 3
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
int
main (void)
{
int *p = 0; /* puntero nulo */
return foo (p);
}
int
foo (int *p)
{
int y = *p;
return y;
}
Este programa intenta referenciar un puntero nulo p, lo cual es una
operación inválida. En la mayorı́a de lo sistemas operativos, esto
causa un fallo del programa.2
Para que sea posible encontrar la causa de un posterior fallo, se
necesitará compilar el programa con la opción ‘-g’:
$ gcc -Wall -g null.es.c
Observe que el puntero nulo sólo causará un problema en tiempo
de ejecución, ası́ la opción ‘-Wall’ no producirá ningún aviso.
Haciendo correr el archivo ejecutable en un sistema x86
GNU/Linux causará que el sistema operativo lo finalice de forma
anormal:
$ ./a.out
Segmentation fault (core dumped)
Siempre que aparezca el mensaje ‘core dumped’, el sistema oper-
ativo producirá un archivo denominado ‘core’ en el directorio en
curso.3 Este archivo core contiene una copia completa de las páginas
2
Históricamente, un puntero nulo correspondı́a con la posición 0 de memoria,
la cual es normalmente restringida por el kernel del sistema operativo. En la
práctica no siempre es ası́ como se trata un puntero nulo, pero el resultado
es habitualmente el mismo.
3
Algunos sistemas, tales como FreeBSD y Solaris, se pueden config-
urados para escribir los archivos core en directorios especı́ficos, p.e.
‘/var/coredumps/’, usando los comandos sysctl y coreadm.
Capı́tulo 5: Compilando para depuración 51
6
http://www.network-theory.co.uk/gcc/intro/
Capı́tulo 6: Compilando con optimización 57
t = sin(u/2)
x = cos(v)*(1+t) + sin(w)*(1-t)
Esta reescritura es denominada eliminación de subexpresiones co-
munes (CSE)1 , y se realiza de forma automática cuando la opti-
mización está activa.2 La eliminación de subexpresiones comunes
es beneficiosa porque simultáneamente incrementa la velocidad y
reduce el tama~ no del código.
6.3 Planificación
El menor nivel de optimización es la planificación, en el cual el
compilador determina el mejor orden para las instrucciones indi-
viduales. La mayorı́a de las CPUs permiten que una o más nuevas
instrucciones comiencen a ejecutarse antes de que otras hallan ter-
minado. Muchas CPUs tienen soporte para segmentación, donde
múltiples instrucciones se ejecutan en paralelo en la misma CPU.
Cuando la planificación está habilitada, las instrucciones pueden
disponer de sus resultados llegando a tener disponible la siguiente
instrucción en el tiempo correcto, y a permitir un máximo de eje-
cución en paralelo. La planificación aumenta la velocidad de un eje-
cutable sin incrementar su tama~ no, pero requiere memoria y tiempo
adicional en sus procesos de compilación (dada su complejidad).
62 Una Introducción a GCC
6.5 Ejemplos
El siguiente programa será usado para demostrar los efectos de los
diferentes niveles de optimización:
#include <stdio.h>
double
powern (double d, unsigned n)
{
double x = 1.0;
unsigned j;
return x;
64 Una Introducción a GCC
int
main (void)
{
double sum = 0.0;
unsigned i;
if (x > 0)
s = 1;
else if (x < 0)
s = -1;
return s;
Capı́tulo 6: Compilando con optimización 67
}
Esta función funciona correctamente para la mayorı́a de argumen-
tos, pero tiene un fallo cuando x es cero —en este caso el valor de
retorno de la variable s será indefinido.
Compilando el programa con la opción ‘-Wall’ solamente no
produce ningún aviso, porque el análisis del flujo de datos no es
llevado a cabo sin optimización:
$ gcc -Wall -c uninit.es.c
Para producir avisos, el programa debe ser compilado con ‘-Wall’
y optimización simultáneamente. En la práctica, el nivel de opti-
mización ‘-O2’ es necesario para obtener buenos avisos:
$ gcc -Wall -O2 -c uninit.c
uninit.c: In function ’sign’:
uninit.c:11:3: warning: ’s’ may be used uninitialized
in this function [-Wuninitialized]
Esto detecta correctamente la posibilidad de que la variable s sea
empleada sin haber sido definida.
Observe que mientras GCC habitualmente encontrará la mayorı́a
de las variables no inicializadas, se estarán usando heurı́sticas que
ocasionalmente fallarán en algunos casos complicados y otras veces
falseando avisos. En esta última situación, es a menudo posible
reescribir las lı́neas relevantes de una forma sencilla que elimine los
avisos y mejore la legibilidad del código fuente.
Capı́tulo 7: Compilando un programa C++ 69
int
main ()
{
std::cout << "!Hola, mundo!\n";
return 0;
}
El programa puede ser compilado con la siguiente lı́nea de comando:
$ g++ -Wall hola.es.cc -o hola
El frontend C++ de GCC usa muchas opciones similares al compi-
lador de C gcc. Además, soporta opciones adicionales para contro-
lar las caracterı́sticas del lenguaje C++, las cuales serán descritas en
este capı́tulo. Observe que el código fuente C++ debe darse en una
de las extensiones válidas para archivos C++ ‘.cc’, ‘.cpp’, ‘cxx’ o
‘.C’ en vez de la extensión ‘.c’ usada por programas C.
El ejecutable resultante puede ser ejecutado de la misma forma
que la versión C, simplemente tecleando su nombre:
70 Una Introducción a GCC
$ ./hola
¡Hola, mundo!
El ejecutable produce la misma salida que la versión C del pro-
grama usando std::cout en vez de la función C printf. Todas las
opciones usadas en comandos gcc en capı́tulos anteriores pueden
aplicarse a g++ sin cambios, al igual que los procedimientos para
compilar y enlazar archivos y librerı́as (usando g++ en vez de gcc,
por supuesto). Una natural diferencia es que la opción ‘-ansi’ re-
quiere conformidad con el estándar C++, en vez de con el estándar
C, cuando es usado con g++.
Observe que los programas que usan archivos objeto C++ deben
ser enlazados con g++, con objeto de suministrar las librerı́as nece-
sarias. Intentar enlazar un archivo objeto C++ con el compilador
de C gcc causará errores del tipo “undefined reference” para las
funciones de la librerı́a estándar de C++:
$ g++ -Wall -c hola.es.cc
$ gcc hola.o (deberı́a usar g++)
hola.o: In function ‘main’:
hola.o(.text+0x1b): undefined reference to ‘std::cout’
.....
hola.o(.eh_frame+0x11):
undefined reference to ‘__gxx_personality_v0’
Las referencias indefinidas a funciones internas de librerı́as en
tiempo de ejecución, tales como __gxx_personality_v0, son prue-
bas del enlazado de archivos objetos C++ con gcc en vez de con
g++.1 Enlazando el mismo archivo objeto con g++ suministra todas
las librerı́as C++ necesarias y produce un ejecutable que funciona:
$ g++ hola.es.o
$ ./a.out
¡Hola, mundo!
Un aspecto que algunas veces causa confusión es que gcc actual-
mente compila código fuente C++ cuando detecta la extensión de
archivos C++, pero no puede enlazar el archivo objeto resultante.
$ gcc -Wall -c hola.es.cc (correcto, en vez de C++)
$ gcc hola.o
hola.o: In function ‘main’:
hola.o(.text+0x1b): undefined reference to ‘std::cout’
Para eliminar este problema, use g++ consistentemente para pro-
gramas C++ y gcc para programas C.
1
Puesto que estas funciones son internas, el error mostrado en este ejemplo
será diferente en otras versiones del compilador.
Capı́tulo 7: Compilando un programa C++ 71
int
main ()
{
string s1 = "!Hola,";
string s2 = "Mundo!";
cout << s1 + " " + s2 << ’\n’;
return 0;
}
El programa puede ser compilado y ejecutado usando los comandos
siguientes:
$ g++ -Wall holastr.es.cc
$./a.out
¡Hola, Mundo!
Observe que de acuerdo con el estándar C++, los archivos cabeceras
de las librerı́as C++ mismas no usan una extensión de archivo. Las
clases en la librerı́a son además definidas dentro del espacio de nom-
bres std, ası́ la directiva using namespace std es necesaria para
acceder a ellas, a menos que el prefijo std:: sea usado en todas
partes (como en la sección anterior).
7.4 Plantillas
Las plantillas facilitan la posibilidad de definir clases C++ que so-
porten técnicas genéricas de programación. Las plantillas se pueden
considerar como una clase poderosa de macro. Cuando una plan-
tilla de clase o función es usada con una clase o tipo especı́fico,
tal como float o int, el código correspondiente a la plantilla es
compilado con el tipo sustituido en los lugares apropiados.
Capı́tulo 7: Compilando un programa C++ 73
int
main ()
{
list<string> list;
list.push_back("Hello");
list.push_back("World");
cout << "List size = " << list.size() << ’\n’;
return 0;
}
No son necesarias opciones especiales para usar las plantillas de
clases de las librerı́as estándar; las opciones de la lı́nea de comandos
para compilar este programa son las mismas de antes:
$ g++ -Wall string.es.cc
$ ./a.out
# items = 2
Observe que el ejecutable creado por g++ usando la librerı́a estándar
de C++ enlazará a la librerı́a compartida ‘libstdc++’, la cual es
suministrada como parte de la instalación por defecto de GCC.
Hay varias versiones de esta librerı́a —si distribuye ejecutables us-
ando la librerı́a estándar de C++ necesita asegurar que los desti-
natarios tienen una versión compatible de ‘libstdc++’, o enlazar
su programa estáticamente usando la opción de lı́nea de comandos
‘-static’.
74 Una Introduccion a GCC
#endif /* BUFFER_H */
El archivo contiene tanto la declaración de la clase como la
definición de las funciones miembro. Esta clase sólo se muestra con
propósitos de demostración y no debe ser considerada un ejemplo
de buena programación. Obsérvese el uso de guardas include, que
comprueban la existencia de una macro BUFFER_H, asegurando que
la definición en el archivo de cabecera será sólo considerada una
vez si el archivo es incluido múltiples veces en el mismo contexto.
El programa siguiente emplea la plantilla de clase Buffer para
crear un buffer de tama~ no 10, almacenando los valores en coma
flotante 0.25 y 1.25 en el buffer:
#include <iostream>
#include "buffer.h"
int
main ()
{
Buffer<float> f(10);
f.insert (0.25);
f.insert (1.0 + f.get(0));
cout << "stored value = " << f.get(0) << ’\n’;
return 0;
}
Las definiciones de la clase de plantilla y sus funciones están
incluidas en el archivo fuente del programa con ‘#include
"buffer.es.h"’ antes de ser usada. El programa puede entonces
ser compilado usando la siguiente lı́nea de comandos:
$ g++ -Wall tprog.es.cc
$ ./a.out
valor almacenado = 1.25
En el momento en que las funciones de la plantilla son usadas en
el código fuente, g++ compila las definiciones apropiadas de los
76 Una Introducción a GCC
int
main (void)
{
double x = 1.0, y = 0.0;
printf ("x/y = %g\n", x / y);
return 0;
}
En aritmética del IEEE el resultado de 1/0 es inf (Infinito). Si
el programa es compilado para un procesador Alpha con la con-
figuración por defecto generará una excepción, que terminará el
programa:
$ gcc -Wall alpha.es.c
$ ./a.out
Floating point exception (en un procesador Alpha)
Usando la opción ‘-mieee’ se asegura una completa conformidad
con el IEEE —La división 1/0 produce correctamente el resultado
inf y el programa continua ejecutándose correctamente:
$ gcc -Wall -mieee alpha.es.c
$ ./a.out
x/y = inf
Observe que los programas que generan excepciones en coma
flotante corren más lentos cuando son compilados con la opción
‘-mieee’, porque las excepciones son manejadas por software en
vez de por hardware.
Capı́tulo 8: Opciones especı́ficas de plataforma 83
void
set_fpu (unsigned int mode)
{
asm ("fldcw %0" : : "m" (*&mode));
}
int
main (void)
{
double a = 3.0, b = 7.0, c;
#ifdef DOUBLE /* Activacion de uso */
set_fpu (0x27F); /* de redondeo en */
#endif /* doble precision */
c = a / b;
if (c == a / b) {
printf ("comparacion exitosa\n");
} else {
printf ("resultado inesperado\n");
}
return 0;
}
En sistemas x86 GNU/Linux la comparación c == a / b puede pro-
ducir un resultado inesperado si c es tomado desde memoria (doble
precisión) mientras que a / b es procesado en precisión extendida,
porque la fracción 3/7 tiene diferentes representaciones en precisión
doble y extendida.
Capıtulo 8: Opciones especificas de plataforma 87
int
main (void)
8
MacOS X (Drawin) en PowerPC usa char con signo, por consistencia con
otras arquitecturas Darwin.
88 Una Introducción a GCC
{
char c = 255;
if (c > 128) {
printf ("el caracter es sin signo (c = %d)\n", c);
} else {
printf ("el caracter es con signo (c = %d)\n", c);
}
return 0;
}
Con un char sin signo, la variable c toma el valor 255, pero con un
char con signo viene a ser −1.
La forma correcta de manipular variables char en C es a través
de las funciones portables declaradas en ‘ctype.h’, tales como
isalpha, isdigit y isblank, en vez de sus valores numéricos. El
comportamiento de las expresiones condicionales no portables tales
como c > ’a’ depende del signado del tipo char. Si se requiere
explı́citamente una versión con signo o sin signo en cierto punto de
un programa, se puede especificar usando signed char o unsigned
char.
For existing programs which assume that char is signed
or unsigned, GCC provides the options ‘-fsigned-char’ and
‘-funsigned-char’ to set the default type of char. Using these
options, the example code above compiles cleanly with ‘-Wall -W’
when char is unsigned:
$ gcc -Wall -W -funsigned-char signed.c
$ ./a.out
char is unsigned (c = 255)
However, when char is signed the value 255 wraps around to −1,
giving a warning when compiled with ‘-Wall -W’:
$ gcc -Wall -W -fsigned-char signed.c
signed.c: In function ‘main’:
signed.c:7: warning: comparison is always false due to
limited range of data type
$ ./a.out
char is signed (c = -1)
El mensaje de aviso “comparison es always true/false due to limited
range of data type” es un sı́ntoma de que el código asume una
definición de char que difiere del tipo actual.
El problema más común en la escritura de código asumiendo el
tipo char con signo ocurre con las funciones getc, fgetc y getchar
(las cuales leen caractéres de un archivo). Tienen un tipo de retorno
Capı́tulo 8: Opciones especı́ficas de plataforma 89
int
main (void)
{
char c;
while ((c = getchar()) != EOF) /* no portable */
{
printf ("leer c = ’%c’\n", c);
}
return 0;
}
Esto sólo funciona en plataformas que por defecto tienen el tipo
char con signo.9 En plataformas que usan char sin signo el mismo
código puede fallar, porque el valor −1 se convierte en un 255
cuando se almacena en un unsigned char. Esto es normalmente
causa de bucles infinitos porque el final del archivo no puede ser
reconocido.10 Para ser portable, el programa debe comprobar el
valor de retorno como un entero antes de forzarlo a char, como a
continuación:
#include <stdio.h>
int
main (void)
{
int i;
while ((i = getchar()) != EOF)
{
unsigned char c = i;
printf ("leer c = ’%c’\n", c);
}
return 0;
}
9
Esto es además un sutil error en plataformas con char con signo —el carácter
ascii 255 es falsamente interpretado como una condición de final de archivo.
10
Si se mostrase, el carácter con código 255 a menudo aparece como ´"y.
90 Una Introducción a GCC
9 Resolución de problemas
GCC proporciona varias opciones de ayuda para ayudar en la res-
olución de problemas con el proceso de compilación. Todas las
opciones descritas en este capı́tulo funciona tanto con gcc como
con g++.
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/i386-linux-gnu/gcc/
/i486-linux-gnu/4.6.1/lto-wrapper
Target: i486-linux-gnu
Configured with: ../src/configure -v
--with-pkgversion=’Debian 4.6.1-4’
--with-bugurl=file:///usr/share/doc/gcc-4.6/
/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++,go
--prefix=/usr --program-suffix=-4.6
--enable-shared --enable-multiarch
--with-multiarch-defaults=i386-linux-gnu
--enable-linker-build-id --with-system-zlib
--libexecdir=/usr/lib/i386-linux-gnu
--without-included-gettext --enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.6
--libdir=/usr/lib/i386-linux-gnu --enable-nls
--enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-plugin
--enable-objc-gc --enable-targets=all
--with-arch-32=i586 --with-tune=generic
--enable-checking=release --build=i486-linux-gnu
--host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.6.1 (Debian 4.6.1-4)
Incluye información en los flags de construcción al mismo compi-
lador y al archivo de configuración instalado, ‘specs’.
--with-bugurl=file:///usr/share/doc/gcc-4.6/
/README.Bugs
--enable-la nguages=c,c++,fortran,objc,obj-c++,go
--prefix=/usr --program-suffix=-4.6 --enable-shared
--enable-multiarch
--with-multiarch-defaults=i386-linux-gnu
--enable-linker-build-id --with-system-zlib
--libexecdir=/usr/lib/i386-linux-gnu
--without-included-gettext --enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.6
--libdir=/usr/lib/i386-linux-gnu --enable-nls
--enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-plugin
--enable-objc-gc --enable-targets=all
--with-arch-32=i586 --with-tune=generic
--enable-checking =release --build=i486-linux-gnu
--host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix gcc version 4.6.1
(Debian 4.6.1-4)
COLLECT_GCC_OPTIONS=’-v’ ’-Wall’ ’-mtune=generic’
’-march=i586’
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/cc1
-quiet -v hola.es.c -quiet -dumpbase hola.es.c
-mtune=generic -march=i586 -auxbase hola.es -Wall -version
-o /tmp/cchpM0t3.s
GNU C (Debian 4.6.1-4) version 4.6.1
(i486-linux-gnu) compiled by GNU C version 4.6.1, GMP
version 5.0.1, MPFR version 3.0.1-p3, MPC version 0.9
warning: GMP header version 5.0.1 differs from library
version 5.0.2.
GGC heuristics: --param ggc-min-expand=46
--param ggc-min-heapsize=31802
ignoring nonexistent directory
"/usr/local/include/i386-linux-gnu"
ignoring nonexistent directory
"/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/../
/../../../../i486-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/include
/usr/local/include
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
/include-fixed
94 Una Introducción a GCC
/usr/include/i386-linux-gnu /usr/include
End of searchlist.
GNU C (Debian 4.6.1-4) version 4.6.1
(i486-linux-gnu) compiled by GNU C version 4.6.1, GMP
version 5.0.1, MPFR version 3.0.1-p3, MPC version 0.9
warning: GMP header version 5.0.1 differs from library
version 5.0.2.
GGC heuristics: --param ggc-min-expand=46
--param ggc-min-heapsize=31802
Compiler executable checksum:
2cfae8623c84fd817bfff483158c4341
COLLECT_GCC_OPTIONS=’-v’ ’-Wall’ ’-mtune=generic’
’-march=i586’ as --32 -o /tmp/ccQxW8a5.o /tmp/cchpM0t3.s
COMPILER_PATH=/usr/lib/i386-linux-gnu/gcc/
/i486-linux-gnu/4.6.1/:
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/:
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/:
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/:
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/
LIBRARY_PATH=/usr/lib/i386-linux-gnu/gcc/
/i486-linux-gnu/4.6.1/:
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
/../../../:
/lib/:/usr/lib/:/usr/lib/i386-linux-gnu/
COLLECT_GCC_OPTIONS=’-v’ ’-Wall’ ’-mtune=generic’
’-march=i586’
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
/collect2
--build-id --no-add-needed --eh-frame-hdr -m elf_i386
--hash-style=both -dynamic -linker /lib/ld-linux.so.2
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
/../../../crt1.o
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
/../../../crti.o
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
/crtbegin.o
-L/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1
-L/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
/../../..
-L/usr/lib/i386-linux-gnu/tmp/ccQxW8a5.o
-lgcc --as-needed -lgcc_s --no-as-needed
-lc -l gcc --as-needed -lgcc_s --no-as-needed
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
Capı́tulo 9: Resolución de problemas 95
/crtend.o
/usr/lib/i386-linux-gnu/gcc/i486-linux-gnu/4.6.1/
/../../../crtn.o
La salida producida por ‘-v’ puede ser útil siempre y cuando haya
un problema con el proceso de compilación en sı́. Esto muestra
las rutas completas usadas para buscar los ficheros de cabecera y
librerı́as, los sı́mbolos de preprocesador predefinidos, y los ficheros
objeto y librerı́as usadas para enlazar.
void
hola (const char * nombre)
{
printf ("!Hola, %s!\n", nombre);
}
El segundo archivo objeto será generado con el archivo fuente
‘adios_fn.es.c’, que contiene la función adios:
#include <stdio.h>
#include "hola.h"
void
bye (void)
{
printf ("!Adios!\n");
}
Ambas funciones usan el archivo de cabecera ‘hola.es.h’, ahora
con un prototipo para la función adios():
100 Una Introducción a GCC
int
main (void)
{
hola ("cualquiera");
adios ();
return 0;
}
Este archivo puede ser compilado con la siguiente lı́nea de comando,
como está descrito en Sección 2.7 [Enlazando con librerı́as externas],
página 18, asumiendo que la librerı́a ‘libhola.a’ está almacenada
en el directorio actual:
1
Observe que ar no requiere el prefijo ‘-’ para estas opciones.
Capıtulo 10: Utilidades relativas al compilador 101
#include <stdio.h>
unsigned int
step (unsigned int x)
{
if (x % 2 == 0)
{
return (x / 2);
}
else
{
return (3 * x + 1);
}
}
unsigned int
nseq (unsigned int x0)
{
unsigned int i = 1, x;
if (x0 == 1 || x0 == 0)
return i;
x = step (x0);
while (x != 1 && x != 0)
{
x = step (x);
i++;
}
return i;
}
int
main (void)
{
unsigned int i, m = 0, im = 0;
if (k > m)
{
m = k;
im = i;
Capı́tulo 10: Utilidades relativas al compilador 103
return 0;
}
Para usar profiling, el programa debe ser compilado y enlazado con
la opción de profiling ‘-pg’:
$ gcc -Wall -c -pg collatz.es.c
$ gcc -Wall -pg collatz.o
Esto creará un ejecutable instrumented que contiene instrucciones
adicionales para registrar el tiempo consumido en cada función.
Si el programa consiste en más de un archivo fuente la opción
‘-pg’ se debe usar cuando se compila cada archivo fuente, y será
usado en el enlazado de los archivos objetos para crear el ejecutable
final (como se muestra anteriormente). Es un error común olvidar
la opción ‘-pg’ en el enlazado, lo cual evita que el profiling registre
mucha información útil.
El ejecutable se debe ejecutar para obtener los datos del profil-
ing:
$ ./a.out
(la salida normal del programa es mostrada)
Mientras está corriendo el ejecutable instrumentado, datos de pro-
filing son silenciosamente escritos en el archivo ‘gmon.out’ en el
directorio actual. Puede se analizado con gprof dando el nombre
del ejecutable como argumento:
$ gprof a.out
Flat profile:
Each sample counts as 0.01 seconds.
% cumul. self self total
time seconds seconds calls us/call us/call name
68.59 2.14 2.14 62135400 0.03 0.03 step
31.09 3.11 0.97 499999 1.94 6.22 nseq
0.32 3.12 0.01 main
La primera columna de los datos muestra que el programa emplea
la mayorı́a de su tiempo (casi del 70%) en la función step, y el
30% en nseq. Consecuentes esfuerzos para decrementar el tiempo
de ejecución debe concentrarse en esta forma. En comparación, el
tiempo empleado en la función main es completamente impercepti-
ble (menos del 1%).
Las otras columnas de la salida suministran información del
número total de llamadas que son hechas a las funciones, y el tiempo
104 Una Introducción a GCC
int
main (void)
{
int i;
return 0;
}
Para habilitar los test de cobertura el programa debe ser compilado
con las siguientes opciones:
$ gcc -Wall -fprofile-arcs -ftest-coverage cov.es.c
Esto creará un ejecutable instrumentado que contiene instrucciones
adicionales que registran el número de veces que cada lı́nea del
programa es ejecutada. La opción ‘-ftest-coverage’ a~ nade in-
strucciones para contabilizar el número de veces que las lı́neas indi-
viduales son ejecutadas, mientras que ‘-fprofile-arcs’ incorpora
instrucciones de código por cada bifurcación del programa. Las in-
strucciones de bifurcación registran la frecuencia de los diferentes
Capı́tulo 10: Utilidades relativas al compilador 105
int
main (void)
{
1 int i;
1 return 0;
1 }
Los contadores de lı́neas pueden verse en la primera columna.
Las lı́neas que no son ejecutadas están marcadas con almohadil-
las ‘######’. El comando ‘grep ’######’ *.gcov’ se puede usar
para encontrar las partes que no están siendo usadas.
Capı́tulo 11: Como funciona el compilador 107
int
main (void)
{
printf ("!Hola, mundo!\n");
return 0;
}
Nótese que no es necesario usar cualquiera de los comandos individ-
uales descritos en esta sección para compilar un programa. Todos
los comandos son ejecutados de manera automática y transparente
por GCC internamente, y puede ser visto usando la opción ‘-v’ de-
scrita antes (véase Sección 9.3 [Compilación verbosa], página 92).
El propósito de este capı́tulo es proporcionar un entendimiento de
cómo el compilador funciona.
Aunque el programa Hola Mundo es muy simple, éste usa
cabeceras externas y librerı́as, y ası́ ejercita todos los pasos im-
portantes del proceso de compilación.
108 Una Introducción a GCC
11.2 El preprocesador
La primera fase del proceso de compilación es el uso del preproce-
sador para expandir macros y ficheros de cabecera incluidos. Para
realizar esta fase, GCC ejecuta el siguiente comando:1
$ cpp hola.es.c > hola.i
El resultado es un fichero ‘hola.i’ que contiene el código fuente con
todas las macros expandidas. Por convención, ficheros preprocesa-
dos son dados por la extensión de fichero ‘.i’ para programas C y
‘.ii’ para programas C++. En la práctica, el fichero preprocesado
no es guardado en disco a menos que la opción ‘-save-temps’ sea
usada.
11.3 El compilador
La siguiente fase del proceso es compilación de código fuente pre-
procesado a lenguaje ensamblador, para un procesador especı́fico.
La opción ‘-S’ dicta a gcc a convertir el código fuente C a lenguaje
ensamblador sin crear un fichero objeto:
$ gcc -Wall -S hola.i
El lenguaje ensamblador resultante es almacenado en el fichero
‘hola.s’. Aquı́ está el lenguaje ensamblador de Hola Mundo para
un procesador Intel x86 (i686):
$ cat hello.s
.file "hello.c"
.section .rodata
.LC0:
.string "Hello, world!"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
1
Como se mencionó antes, el preprocesador está integrado en el compilador
en versiones recientes de GCC. Conceptualmente, el proceso de compilación
es el mismo que ejecutar el preprocesar como una aplicación separada.
Capı́tulo 11: Como funciona el compilador 109
11.4 El ensamblador
El propósito de un ensamblador es convertir lenguaje ensamblador
a código máquina y generar un fichero objeto. Cuando hay lla-
madas a funciones externas en el fichero fuente de ensamblador, el
ensamblador deja las direcciones las funciones externas indefinidas,
para ser rellenadas después por el enlazador. El ensamblador puede
ser invocado con la siguiente lı́nea de comandos:
$ as hola.s -o hola.o
As with GCC, the output file is specified with the ‘-o’ option. The
resulting file ‘hello.o’ contains the machine instructions for the
Hello World program, with an undefined reference to puts.
11.5 El enlazador
La fase final de compilación es el enlace de ficheros objeto para
crear un ejecutable. En la práctica, un ejecutable requiere muchas
funciones externas del sistema y de librerı́as C. Por consiguiente,
los comandos de enlace actuales usados internamente por GCC son
complicados. Por ejemplo, el comando completo para enlazar el
programa Hola Mundo es:2
2
El comando preciso varı́a dependiendo de la versión de gcc y el sistema
operativo. Versiones recientes de gcc usan wrapper llamado collect2 que
hace algún trabajo adicional antes de llamar a ld.
110 Una Introducción a GCC
$ ld -dynamic-linker /lib/ld-linux.so.2 \
/usr/lib/crt1.o \
/usr/lib/crti.o \
/usr/lib/gcc/i486-linux-gnu/4.3/crtbegin.o \
-L/usr/lib/gcc/i486-linux-gnu/4.3 hola.o \
-lgcc -lgcc_eh \
-lc /usr/lib/gcc/i486-linux-gnu/4.3/crtend.o \
/usr/lib/crtn.o
Afortunadamente nunca se necesita escribir el comando de arriba
directamente —el proceso entero de enlace es manejado de manera
transparente por gcc cuando se invoca como sigue:
$ gcc hola.o
Esto enlaza el fichero objeto ‘hola.o’ a la librerı́a estándar de C, y
produce un fichero ejecutable ‘a.out’:
$ ./a.out
¡Hola, mundo!
Un fichero objeto para un programa C++ puede ser enlazado a la
librerı́a estándar C++ del mismo modo con un simple comando g++.
Capı́tulo 12: Examinado archivos compilados 111
Intel 80386
Procesador para el cual ha sido complilado el archivo
ejecutable.
version 1 (SYSV)
Esta es la versión del formato interno del archivo.
dynamically linked
El ejecutable emplea librerı́as compartidas dinámicas
(statically linked indicarı́a que el programa fué en-
lazado estáticamente, en el ejemplo usando la opción
‘-static’)
not stripped
El ejecutable contiene una tabla de sı́mbolos ( ésta
puede ser eliminada usando el comando strip).
El comando file puede ser usado con archivos objeto, donde dará
una salida similiar. El estándar POSIX2 para sistemas Unix define
el comportamiento del comando file.
int
main (void)
{
printf ("!Hola Mundo!\n");
return 0;
}
El programa de arriba intenta incluir el fichero in-
existente ‘stdoi.h’ dando el error ‘stdoi.h: No such
file or directory’. El nombre de fichero correcto es
‘stdio.h’.
macro or ’#include’ recursion too deep
#include nested too deeply
Este error ocurre si el preprocesador encuentra demasi-
adas directivas ‘#include’ anidadas. Esto es normal-
mente causado por dos ó más ficheros intentando incluir
otro, provocando una recursión infinita.
Ejemplo:
/* foo.h */
#include "bar.h"
...
116 Una Introduccion a GCC
/* bar.h */
#include "foo.h"
...
La solución a este problema es asegurar que los ficheros
no se incluyen mutuamente, o usar ‘guardas include’
(véase Sección 7.4.2 [Proporcionando sus propias plan-
tillas], página 74 por ejemplo).
invalid preprocessing directive #...
Este error indica que el preprocesador encontró un co-
mando # irreconocible.
Ejemplo:
#if FOO
int x = 1;
#elsif BAR /* deberia ser #elif */
int x = 2;
#else
int x = 3;
#endif
La sintaxis de preprocesador requiere #elif para la
condición “else if” en los bloques #if, en vez de
#elseif. En el ejemplo de arriba ocurre un error de
directiva inválida en el incorrecto uso de #elseif, pero
solo cuando FOO está definido (en otros casos el pre-
procesador ignora cualquiera de la sentencia #else).
int
main (void)
{
int i;
j = 0; /* no declarado */
return j;
}
La variable j no está declarada y saltará el error ‘j’
undeclared.
parse error before ‘...’
expected ’;’ before ‘...’
syntax error
Este mensaje de error ocurre cuando el compilador en-
cuentra una entrada inesperada, p.e. secuencias de car-
acteres que no siguen la sintaxis del lenguaje. Este
mensaje de error salta por la ausencia de paréntesis o
llaves de cierre o punto y coma precediendo la lı́nea de
error, o una palabra reservada inválida.
Ejemplo:
#include <stdio.h>
int
main (void)
{
printf ("!Hola ") /*falta punto y coma*/
printf ("Mundo!\n");
return 0;
}
Aquı́ hay una ausencia de punto y coma después de la
primera llamada a printf, dando un error de parseo.
parse error at end of input
expected declaration or statement at end of input
Este error ocurre si el compilador encuentra un final de
archivo inesperadamente, tal como cuando se analizan
un número no balanceado de llaves de apertura y cierre.
Es a menudo causado por la ausencia de un cierre de
llaves en algún lugar.
Ejemplo:
118 Una Introduccion a GCC
#include <stdio.h>
int
main (void)
{
if (1) {
printf ("!Hola Mundo!\n");
return 0; /* no cierra llave */
}
Una llave de cierre adicional es necesaria en este pro-
grama para prevenir el error expected declaration
or statement at end of input.
warning: implicit declaration of function ‘...’
warning: incompatible implicit declaration of built-in
function ‘...’
Este aviso es generado cuando una función es usada sin
un prototipo declarado. Esto puede ser causado por la
falta de inclusión de una archivo de cabeceras, o si no
olvidando suministrar un prototipo de función.
Ejemplo:
int
main (void)
{
printf ("!Hola Mundo!\n"); /*hace falta*/
return 0; /*fichero de cabecera*/
}
El archivo de cabeceras del sistema ‘stdio.h’ no está
incluido, ası́ que el prototipo de la función printf no ha
sido declarado. El programa necesita una lı́nea inicial
#include <stdio.h>.
unterminated string or character constant
missing terminating " character
Este error es causado por unas comillas de apertura
de una cadena o carácter que no tiene su correspondi-
ente comillas de cierre. Las comillas deben aparecer en
parejas coincidentes, como una comilla simple ’a’ para
caracteres o dobles comillas "aaa" para cadenas.
Ejemplo:
Capı́tulo 13: Mensajes comunes de error 119
#include <stdio.h>
int
main (void)
{ /* No cierra comillas */
printf ("!Hola Mundo!\n);
return 0;
}
Las dobles comillas de apertura de la cadena en este
programa no tiene su correspondiente dobles comillas
de cierre, ası́ el compilador lee el resto del archivo como
parte de la cadena.
character constant too long
En C y C++ los caracteres son escritos usando simples
comillas, p.e. ’a’ da el código ASCII de la letra a (67),
y ’\n’ da el código ASCII de nueva lı́nea (10). Este
error ocurre si unas comillas simples son usadas para
encerrar más de un carácter.
Ejemplo:
#include <stdio.h>
int
main (void)
{ /* Uso de comillas correctas */
printf (’!Hola Mundo!\n’);
return 0;
}
El programa anterior confunde las comillas simples y
dobles. Una secuencia de caracteres se debe escribir
con comillas dobles, p.e. "¡Hola Mundo!". Este mismo
problema ocurre en el siguiente programa C++,
#include <iostream>
int
main (void)
{
std::cout << ’Hello World!\n’; // wrong quotes
return 0;
}
Este error puede ocurrir si la barra de división y la
barra invertida son confundidas en una secuencia de
120 Una Introduccion a GCC
#include <stdlib.h>
int
main (void)
{
int i = NULL; /* incorrecto */
return 0;
}
En C, la macro NULL es definida como ((void *)0) en
‘stdio.h’ y solamente deberı́a ser usada en un contexto
de puntero.
dereferencing pointer to incomplete type
Este error ocurre cuando un programa intenta acceder
a un elemento de una estructura a través de un puntero
sin que la estructura haya sido declarada anteriormente.
En C y C++ es posible declarar punteros a estructuras
antes de la declaración de las estructuras, proporcio-
nando los punteros que no son referenciados —Esto es
conocido como declaración avanzada (forward declara-
tion).
Ejemplo:
struct btree * data;
int
main (void)
{
data->size = 0; /* tipo incompleto */
return 0;
}
Este programa tiene una declaración posterior de data
como estructura btree. Sin embargo, la definición de
la estructura es necesaria antes de que el puntero pueda
ser referenciado para acceder a sus miembros individ-
ualmente.
warning: unknown escape sequence ‘...’
Este error es causado por un incorrecto uso del carácter
de escape en una cadena. Las secuencias de escape
válidas son:
\n nueva lı́nea \t tabulador
\b retroceso \r retorno de carro
\f alimentación de lı́nea \v tabulador vertical
122 Una Introducción a GCC
\a alerta (campana)
Las combinaciones \\, \’, \" y \? pueden ser usadas
para caracteres individuales. Las secuencias de escape
pueden usar códigos octales \0–\377 y códigos hexadec-
imales \0x00–\0xFF.
Ejemplo:
#include <stdio.h>
int
main (void)
{
printf ("!HOLA MUNDO!\N");
return 0;
}
La secuencia de escape \N en el programa anterior
es inválida —La correcta secuencia de escape para el
carácter de nueva lı́nea es \n.
warning: suggest parentheses around assignment used as
truth value
Este aviso resalta un potencial serio error, usando el
operador ‘=’ en vez del operador de comparación ‘==’ en
el test de la instrucción condicional o en otra expresión
lógica. Mientras el operador de asignación puede ser
usado como parte de un valor lógico, éste es raramente
el comportamiento deseado.
Ejemplo:
#include <stdio.h>
int
main (void)
{
int i = 0;
if (i = 1) { /* = deberia ser == */
printf ("resultado inesperado\n");
}
return 0;
}
El test anterior deberı́a haberse escrito como if (i ==
1), en otro caso la variable i será puesta a 1 por la
evaluación de la misma instrucción if. El operador ‘=’
tanto asigna como devuelve el valor de su parte derecha,
Capıtulo 13: Mensajes comunes de error 123
int
display (const char * str)
{
printf ("%s\n", str);
}
El programa anterior alcanza el final de la función
display, la cual retorna un tipo int, sin una in-
strucción return. Una lı́nea adicional como return
0; es necesaria.
Cuando se usa gcc la función main de un programa C
debe devolver un valor de tipo int (el estado de salida
del programa). En C++ la instrucción return puede
ser omitida en la función main —el valor de retorno de
la función main por defecto es 0 si no es especificado.
warning: unused variable ‘...’
warning: unused parameter ‘...’
Este aviso indica que una variable ha sido declarada
como variable local o parámetro de una función, pero no
ha sido usada en ningún lugar. Una variable no usada
puede ser el resultado de un error de programación, tal
como usar accidentalmente el nombre de una variable
en vez de otro.
Ejemplo:
124 Una Introducción a GCC
int
foo (int k, char * p)
{
int i, j;
j = k;
return j;
}
En este programa la variable i y el parámetro p nunca
son usados. Observe que las variables no usadas son
informadas por al opción ‘-Wall’, mientras que los
parámetros no usados sólo se muestran con ‘-Wall -W’.
warning: passing arg of ... as ... due to prototype
Este aviso ocurrre cuando una función es llamada
con un argumento de diferente tipo al especificado
en su prototipo. La opción ‘-Wconversion’ es nece-
saria para habilitar estos avisos. Vea la descripción de
‘-Wconversion’ en Sección 3.5 [Opciones de aviso adi-
cionales], página 37 para ver un ejemplo.
warning: assignment of read-only location
warning: cast discards qualifiers from pointer target
type
warning: assignment discards qualifiers ...
warning: initialization discards qualifiers ...
warning: return discards qualifiers ...
Estos avisos ocurren cuando un puntero es usado de
manera incorrecta, violando un calificador de tipo tal
como const. Los datos accedidos a través de un pun-
tero marcado como const no se modificará, y el pun-
tero en sı́ sólo puede ser asignado a otros punteros que
también son marcados como const.
Ejemplo:
char *
f (const char *s)
{
*s = ’\0’; /* asigna dato en modo solo */
return s; /* lectura descartando const */
}
Este programa intenta modificar datos constantes, y
descartar la propiedad const del argumento s en el
valor devuelto.
Capı́tulo 13: Mensajes comunes de error 125
int
main (void)
{
fprintf (stream, "!Hola Mundo!\n");
return 0;
}
Este programa intenta inicializar dos variables desde
otras variables. En particular, no se requiere al flujo
stdout ser una constante por el estándar de C (aunque
en algunos sistemas es una constante). Nótese que ini-
cializadore no constantes son permitidos en C++.
int
main (void)
{
printf ("Hello World!\n");
return 0;
}
126 Una Introducción a GCC
int
main (void)
{
foo();
return 0;
}
Si este programa está compilado sin ser enlazado a una
librerı́a o fichero objeto conteniendo la función foo()
habrá una indefinida referencia de error.
/usr/lib/crt1.o(.text+0x18): undefined reference to
‘main’
Este error es un caso especial del error de debajo,
cuando la función perdida es main. En C y C++,
cada programa debe tener una función main (dónde
la ejecución comienza). Cuando se compila un fichero
fuente individual sin una función main, usa la opción
‘-c’ (véase Sección 2.4.1 [Creando archivos objeto desde
archivos fuente], página 13).
Capı́tulo 13: Mensajes comunes de error 127
Illegal instruction
Este error es producido por el sistema operativo cuando
se encuentra una instrucción máquina ilegal. Esto
ocurre cuando el código ha sido compilado para una
arquitectura especı́fica y se ejecuta en otra.
Capı́tulo 14: Obteniendo ayuda 129
14 Obteniendo ayuda
Si encuentras un problema no cubierto por esta introducción, hay
varios manuales de referencia que describen GCC y asuntos rela-
cionados con el lenguaje en más detalle (véase [Lectura adicional],
página 131). Estos manuales contienen respuestas a preguntas co-
munes, y un cuidadoso estudio de éstas normalmente producirán
una solución.
De otro modo, hay muchas compa~ nı́as y consultores quienes ofre-
cen soporte comercial para cuestiones de programación relativas a
GCC por horas o de forma contı́nua. En los negocios esto puede ser
un camino de costes efectivo para obtener soporte de alta calidad.
Un directorio de compa~ nı́as que dan soporte al software libre
y sus precios actualizados puede ser encontrado en el sitio web1
del Proyecto GNU. Con software libre, el soporte comercial está
disponible en un mercado libre —compa~ nı́as de servicios compiten
en calidad y precio, y los usuarios no están atados a una deter-
minada. En contraste, el soporte para el software privativo está
normalmente sólo disponible desde el vendedor original.
Un soporte comercial de alto nivel para GCC está disponible
desde compa~ nı́as involucradas en el desarrollo del conjunto de her-
ramientas del compilador de GNU por sı́ mismo. Un listado de
estas compa~ nı́as puede ser encontrado en la sección de “Compa~ nı́as
de Desarrollo” de la página web de la editorial para este libro.2 Es-
tas compa~ nı́as pueden proporcionar servicios tales como extender
GCC para generar código para nuevos procesadores o para arreglar
errores encontrados en el compilador.
1
http://www.gnu.org/prep/service.html
2
http://www.network-theory.co.uk/gcc/intro/
Lectura adicional 131
Lectura adicional
La guı́a definitiva para GCC es el manual oficial de referencia, “Us-
ing GCC”, publicado por GNU Press:
Using GCC (for GCC version 3.3.1) por Richard M. Stall-
man y the GCC Developer Community (Publicado por
GNU Press, ISBN 1-882114-39-6)
Este manual es esencial para cualquiera que trabaje con GCC
porque describe cada opción en detalle. Nótese que el manual
está actualizado cuando nuevas versiones de GCC llegan a estar
disponibles, ası́ el número ISBN puede cambiar en el futuro.
Si eres nuevo programando con GCC también querrás aprender a
usar el Depurador de GNU GDB, y a cómo compilar largos progra-
mas fácilmente con GNU Make. Éstas herramientas son descritas
en los siguientes manuales:
Debugging with GDB: The GNU Source-Level Debugger
por Richard M. Stallman, Roland Pesch, Stan Shebs, et
al. (Publicado por GNU Press, ISBN 1-882114-88-4)
GNU Make: A Program for Directing Recompilation por
Richard M. Stallman y Roland McGrath (Publicado por
GNU Press, ISBN 1-882114-82-5)
Para una efectiva programación en C es también esencial tener
buenos conocimientos de la librerı́a estándar de C. El siguientes
manual documenta todas las funciones en la GNU C Library:
The GNU C Library Reference Manual por Sandra Loose-
more con Richard M. Stallman, et al (2 vols) (Publicado
por GNU Press, ISBN 1-882114-22-1 y 1-882114-24-8)
Asegúrate de visitar el sitio web http://www.gnupress.org/ para
las últimas ediciones impresas de manuales publicados por GNU
Press. Los manuales pueden ser adquiridos online usando una tar-
jeta de crédito en el sitio web de la FSF1 además de estar dispon-
bles para su compra a través de la mayorı́a de las librerı́as usando
ISBN. Manuales publicados por GNU Press financian la Free Soft-
ware Foundation y el Proyecto GNU.
Información acerca de comandos de shell, variables de entorno
y reglas de comillas en shell puede ser encontrada en el siguiente
libro:
The GNU Bash Reference Manual por Chet Ramey y
Brian Fox (Publicados por Network Theory Ltd, ISBN
0-9541617-7-7)
1
http://order.fsf.org/
132 Una Introducción a GCC
2
http://www.network-theory.co.uk/gcc/intro/
Reconocimientos 133
Reconocimientos
Muchas personas han contribuido a este libro, y es importante recor-
dar sus nombres aquı́:
Gracias a Gerald Pfeifer, por su cuidadosa revisión y numerosas
sugerencias para mejorar el libro.
Gracias a Andreas Jaeger, por la información acerca de AMD64
y soporte multi-arquitectura, y sus muchos útiles comentarios.
Gracias a David Edelsohn, por la información acerca de la serie
de procesadores POWER/PowerPC.
Gracias a Jamie Lokier, por investigar.
Gracias a Martin Leisner, Mario Pernici, Stephen Compall y
Nigel Lowry, por sus útiles correcciones.
Gracias a Gerard Jungman, por sus útiles comentarios.
Gracias a Steven Rubin, por generar la imagen del chip para la
cubierta con Electric.
Y de manera más importante, gracias a Richard Stallman, fun-
dador del Proyecto GNU, por escribir GCC y hacer que sea software
libre.
Organizaciones de software libre 135
The “Cover Texts” are certain short passages of text that are listed, as Front-
Cover Texts or Back-Cover Texts, in the notice that says that the Document is
released under this License. A Front-Cover Text may be at most 5 words, and a
Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy, repre-
sented in a format whose specification is available to the general public, that is
suitable for revising the document straightforwardly with generic text editors or
(for images composed of pixels) generic paint programs or (for drawings) some
widely available drawing editor, and that is suitable for input to text formatters
or for automatic translation to a variety of formats suitable for input to text
formatters. A copy made in an otherwise Transparent file format whose markup,
or absence of markup, has been arranged to thwart or discourage subsequent
modification by readers is not Transparent. An image format is not Transparent
if used for any substantial amount of text. A copy that is not “Transparent” is
called “Opaque”.
Examples of suitable formats for Transparent copies include plain ascii without
markup, Texinfo input format, LaTEX input format, SGML or XML using a
publicly available DTD, and standard-conforming simple HTML, PostScript or
PDF designed for human modification. Examples of transparent image formats
include PNG, XCF and JPG. Opaque formats include proprietary formats that
can be read and edited only by proprietary word processors, SGML or XML
for which the DTD and/or processing tools are not generally available, and the
machine-generated HTML, PostScript or PDF produced by some word processors
for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such
following pages as are needed to hold, legibly, the material this License requires
to appear in the title page. For works in formats which do not have any title
page as such, “Title Page” means the text near the most prominent appearance
of the work’s title, preceding the beginning of the body of the text.
A section “Entitled XYZ” means a named subunit of the Document whose title
either is precisely XYZ or contains XYZ in parentheses following text that trans-
lates XYZ in another language. (Here XYZ stands for a specific section name
mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”,
or “History”.) To “Preserve the Title” of such a section when you modify the
Document means that it remains a section “Entitled XYZ” according to this
definition.
The Document may include Warranty Disclaimers next to the notice which states
that this License applies to the Document. These Warranty Disclaimers are con-
sidered to be included by reference in this License, but only as regards disclaiming
warranties: any other implication that these Warranty Disclaimers may have is
void and has no effect on the meaning of this License.
2. VERBATIM COPYING
You may copy and distribute the Document in any medium, either commercially
or noncommercially, provided that this License, the copyright notices, and the
license notice saying this License applies to the Document are reproduced in
all copies, and that you add no other conditions whatsoever to those of this
License. You may not use technical measures to obstruct or control the reading
or further copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough number of
copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may
publicly display copies.
Licencia para documentación libre GNU 139
3. COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have printed
covers) of the Document, numbering more than 100, and the Document’s license
notice requires Cover Texts, you must enclose the copies in covers that carry,
clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover,
and Back-Cover Texts on the back cover. Both covers must also clearly and
legibly identify you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and visible. You may
add other material on the covers in addition. Copying with changes limited to
the covers, as long as they preserve the title of the Document and satisfy these
conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should
put the first ones listed (as many as fit reasonably) on the actual cover, and
continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than
100, you must either include a machine-readable Transparent copy along with
each Opaque copy, or state in or with each Opaque copy a computer-network lo-
cation from which the general network-using public has access to download using
public-standard network protocols a complete Transparent copy of the Document,
free of added material. If you use the latter option, you must take reasonably
prudent steps, when you begin distribution of Opaque copies in quantity, to en-
sure that this Transparent copy will remain thus accessible at the stated location
until at least one year after the last time you distribute an Opaque copy (directly
or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document
well before redistributing any large number of copies, to give them a chance to
provide you with an updated version of the Document.
4. MODIFICATIONS
You may copy and distribute a Modified Version of the Document under the
conditions of sections 2 and 3 above, provided that you release the Modified
Version under precisely this License, with the Modified Version filling the role
of the Document, thus licensing distribution and modification of the Modified
Version to whoever possesses a copy of it. In addition, you must do these things
in the Modified Version:
A. Use in the Title Page (and on the covers, if any) a title distinct from that of
the Document, and from those of previous versions (which should, if there
were any, be listed in the History section of the Document). You may use
the same title as a previous version if the original publisher of that version
gives permission.
B. List on the Title Page, as authors, one or more persons or entities respon-
sible for authorship of the modifications in the Modified Version, together
with at least five of the principal authors of the Document (all of its prin-
cipal authors, if it has fewer than five), unless they release you from this
requirement.
C. State on the Title page the name of the publisher of the Modified Version,
as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications adjacent to the
other copyright notices.
140 Una Introducción a GCC
5. COMBINING DOCUMENTS
You may combine the Document with other documents released under this Li-
cense, under the terms defined in section 4 above for modified versions, provided
that you include in the combination all of the Invariant Sections of all of the
original documents, unmodified, and list them all as Invariant Sections of your
combined work in its license notice, and that you preserve all their Warranty
Disclaimers.
The combined work need only contain one copy of this License, and multiple
identical Invariant Sections may be replaced with a single copy. If there are
multiple Invariant Sections with the same name but different contents, make the
title of each such section unique by adding at the end of it, in parentheses, the
name of the original author or publisher of that section if known, or else a unique
number. Make the same adjustment to the section titles in the list of Invariant
Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History” in the vari-
ous original documents, forming one section Entitled “History”; likewise combine
any sections Entitled “Acknowledgements”, and any sections Entitled “Dedica-
tions”. You must delete all sections Entitled “Endorsements.”
6. COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this License
in the various documents with a single copy that is included in the collection,
provided that you follow the rules of this License for verbatim copying of each of
the documents in all other respects.
You may extract a single document from such a collection, and distribute it
individually under this License, provided you insert a copy of this License into
the extracted document, and follow this License in all other respects regarding
verbatim copying of that document.
7. AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate and in-
dependent documents or works, in or on a volume of a storage or distribution
medium, is called an “aggregate” if the copyright resulting from the compila-
tion is not used to limit the legal rights of the compilation’s users beyond what
the individual works permit. When the Document is included in an aggregate,
this License does not apply to the other works in the aggregate which are not
themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the
Document, then if the Document is less than one half of the entire aggregate, the
Document’s Cover Texts may be placed on covers that bracket the Document
within the aggregate, or the electronic equivalent of covers if the Document is in
electronic form. Otherwise they must appear on printed covers that bracket the
whole aggregate.
8. TRANSLATION
Translation is considered a kind of modification, so you may distribute transla-
tions of the Document under the terms of section 4. Replacing Invariant Sec-
tions with translations requires special permission from their copyright holders,
but you may include translations of some or all Invariant Sections in addition to
the original versions of these Invariant Sections. You may include a translation
of this License, and all the license notices in the Document, and any Warranty
Disclaimers, provided that you also include the original English version of this
License and the original versions of those notices and disclaimers. In case of a
142 Una Introducción a GCC
disagreement between the translation and the original version of this License or
a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”, “Dedications”,
or “History”, the requirement (section 4) to Preserve its Title (section 1) will
typically require changing the actual title.
9. TERMINATION
You may not copy, modify, sublicense, or distribute the Document except as
expressly provided for under this License. Any other attempt to copy, modify,
sublicense or distribute the Document is void, and will automatically terminate
your rights under this License. However, parties who have received copies, or
rights, from you under this License will not have their licenses terminated so
long as such parties remain in full compliance.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions of the GNU Free
Documentation License from time to time. Such new versions will be similar in
spirit to the present version, but may differ in detail to address new problems or
concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Doc-
ument specifies that a particular numbered version of this License “or any later
version” applies to it, you have the option of following the terms and conditions
either of that specified version or of any later version that has been published (not
as a draft) by the Free Software Foundation. If the Document does not specify a
version number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
Índice
T
utilidades relativas al compilador
‘t’, opción para ver la tabla de . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
contenidos de una librerı́a. . . 100 utilidades, relativas al compilador
tabla de contenidos, en librerı́as ar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
. . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
tabla de contenidos, error de
desbordamiento en AIX . . . . . . 83 V
tabla de sı́mbolos . . . . . . . . . . . . . . . . 49
‘v’, opción para compilación verbosa
tabla de sı́mbolos, examinando con
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
nm . . . . . . . . . . . . . . . . . . . . . . . . . . 112
valor por defecto, de macro definido
tabulador, en makefiles . . . . . . . . . . . 16
con ‘-D’ . . . . . . . . . . . . . . . . . . . . . 46
tama~ no de palabra, en UltraSPARC
valor, de macro . . . . . . . . . . . . . . . . . . 44
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
variable con signo convertida a sin
tama~ no variable, arrays . . . . . . . . . . 33
signo, aviso de . . . . . . . . . . . . . . . 38
tama~ no, optimización por, ‘-Os’ . . 63
variable no declarada . . . . . . . . . . . . 116
tama~ o de palabra, determinado desde
variable no inicializada, aviso de . . 67
el archivo ejecutable . . . . . . . . 111
variable oculta . . . . . . . . . . . . . . . . . . . 39
tcsh, comando limit. . . . . . . . . . . . . . 51
variable sin signo convertida a con
terminación, anormal (core dumped)
signo, aviso de . . . . . . . . . . . . . . . 38
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
test de cobertura, con gcov . . . . . . 104 variable, aviso de uso sin inicializar
Thumb, formato alternativo de . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
código en ARM . . . . . . . . . . . . . . 84 variables de entorno . . . . . . . . . . . 8, 29
tiempo de ejecución, midiendo con variables de entorno, asignación
comando time . . . . . . . . . . . . . . . 64 permanente . . . . . . . . . . . . . . . . . . 29
tipo devuelto, no válido . . . . . . . . . . 36 variables de entorno, extendiendo
traductores, desde C++ a C, una ruta existente . . . . . . . . . . . 30
comparados con g++ . . . . . . . . . 69 variables de entorno, por defecto
traza, mostrando . . . . . . . . . . . . . . . . . 52 rutas de búsqueda . . . . . . . . . . . 26
‘tune’, opción para una máquina variables de shell . . . . . . . . . . . 8, 26, 29
especı́fica . . . . . . . . . . . . . . . . . . . . 79 variables shell, asignación
typeof, palabra reservada de la permanente . . . . . . . . . . . . . . . . . . 29
extensión GNU C . . . . . . . . . . . . 32 variables, en make . . . . . . . . . . . . . . . . 16
vax, palabra reservada de la
extensión GNU C . . . . . . . . . . . . 32
U void return, uso incorrecto de . . . . 36
UltraSPARC, modo 32 bits versus
modo 64 bits . . . . . . . . . . . . . . . . 83
unix, palabra reservada de la W
extensión GNU C . . . . . . . . . . . . 32 ‘W’, opción que habilita avisos
unknown escape sequence . . . . . . . 121 adicionales. . . . . . . . . . . . . . . . . . . 37
unterminated string or character ‘Wall’, opción que habilita los avisos
constant . . . . . . . . . . . . . . . . . . . . 118 comunes . . . . . . . . . . . . . . . . . . . . . . 9
unused parameter warning . . . . . . 123 ‘Wcast-qual’, opción de aviso de
Usando GCC (Manual de Referencia) casts eliminando calificadores
. . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
uso de memoria virtual, limitando ‘Wconversion’, opción de aviso de
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 conversiones de tipos . . . . . . . . 38
uso de memoria, limitando . . . . . . . 97 ‘Weffc++’, opción. . . . . . . . . . . . . . . . . 71
Índice 157