- Uned Denia
ndice de contenidos
Ejercicio 6.3:...................................................................2
Ejercicio 6.4:................................................................................................................................2
Ejercicio 6.5:................................................................................................................................2
Ejercicio 6.6:................................................................................................................................3
Ejercicio 6.7:................................................................................................................................3
Ejercicio 6.9:................................................................................................................................3
Ejercicio 6.10:..............................................................................................................................4
Ejercicio 6.11:...............................................................................................................................4
Ejercicio 6.12:..............................................................................................................................4
Ejercicio 6.14:..............................................................................................................................5
Ejercicio 6.15:..............................................................................................................................5
Ejercicio 6.17:..............................................................................................................................6
Ejercicio 6.18:..............................................................................................................................6
Ejercicio 6.19:..............................................................................................................................6
Ejercicio 6.22:..............................................................................................................................7
Ejercicio 6.23:..............................................................................................................................7
Ejercicio 6.25:..............................................................................................................................7
Ejercicio 6.26:..............................................................................................................................7
Ejercicio 6.28:..............................................................................................................................8
Ejercicio 6.29:..............................................................................................................................8
Ejercicio 6.30:..............................................................................................................................9
Ejercicio 6.34:..............................................................................................................................9
Ejercicio 6.36:..............................................................................................................................9
Ejercicio 6.37:............................................................................................................................10
Ejercicio 6.38:............................................................................................................................10
Ejercicio 6.44:............................................................................................................................10
Ejercicio 6.46:.............................................................................................................................11
Ejercicio 6.49:.............................................................................................................................11
Ejercicio 6.51:............................................................................................................................12
1/13
Ejercicio 6.4:
Dadas las declaraciones en C:
Struct
{ int i;
Double j;
} x, y;
Struct
{ int i;
Double j;
} z;
La asignacin x=z genera un error de compilacin, pero la asignacin x=y no lo hace. Por qu?
Proponga dos formas diferentes de arreglar el cdigo anterior de manera que x=z funcione. Cul es la
mejor manera y por qu?
La razn es porque x e y tienen el mismo tipo, puesto que estn definidas en la misma declaracin.
La variable z es de un tipo diferente, puesto que est declarada en una declaracin struct separada.
Una forma de solucionar el problema es aadir z a la definicin de x e y, esto es:
Struct
{ Int i;
Double j;
} x, y, z;
Esta no es una buena solucin, puesto que el tipo de datos de x, y y z son annimos.
Una forma mejor es dar al tipo de datos struct un nombre y despus definir las variables x, y y z
como variables de dicho tipo.
Struct S
{ Int i;
Double j;
};
Struct S x, y, z;
Ejercicio 6.5:
Suponga que tenemos dos arreglos en C:
Int x [10];
Int y [10];
2/13
En esta versin, x se convierte en un alias de y (por lo menos hasta que x sea reasignada)
Ejercicio 6.6:
Dadas las siguientes declaraciones de variables en C/C++:
enum {one} x;
enum {two} y;
La asignacin x=y es correcta en C, pero genera un error de compilacin en C++. Explique las razones.
El motivo es que las declaraciones enum no son constructores de tipos realmente en C, pero son
atajos de definiciones de subrangos de enteros.
En C++ enum es un constructor de tipo de datos, por lo que diferentes definiciones de enum crean
diferentes tipos, al igual que diferentes struct crean diferentes tipos.
Ejercicio 6.7:
Dadas las siguientes declaraciones de variables de funcin en C/C++:
Int (*f) (int);
Int (*g) (int);
Int (*h) (char);
La asignacin f=g es correcta en C y C++, pero la asignacin h=g genera una advertencia del compilador
en C y en C++ un error de compilacin. Explique las razones.
Tanto C como C++ usan la equivalencia estructural para tipos de funciones, por eso, la asignacin f=g
o g=f es correcta, ya que los tipos son estructuralmente idnticos.
Por otro lado, h tiene un tipo diferente (char) en su parmetro, y por ello no existe equivalencia de
tipo.
As, la asignacin h=g genera una advertencia de incompatibilidad en C, y un error en C++ puesto
que ste es ms estricto en las conversiones de tipos.
De hecho, esta asignacin puede o no funcionar, dependiendo del entorno de ejecucin.
Los caracteres pueden verse como enteros, pero pueden tener diferente tamao, y esto ocasionara
un error.
Ejercicio 6.9:
Considere la ecuacin de conjunto: x char =
(a) Demuestre que cualquier conjunto que satisfaga a esta ecuacin debe ser infinito.
(b) Demuestre que cualquier elemento de un conjunto que satisfaga a esta ecuacin debe contener un
nmero infinito de caracteres.
(c) Existe una solucin que sea la ms pequea a esta ecuacin?
Supongamos que es finito y que contiene n elementos.
Entonces la expresin x char es tambin finita y tiene ms elementos de los que tiene (si char
tiene 128 elementos, entonces x char tiene n veces 128 elementos)
Pero esto contradice la expresin x char = . Por tanto debe ser infinito.
Considere un elemento x del conjunto , y suponga que satisface la ecuacin = x char. Entonces
x=(x', c) para algn x' en y algn carcter c. Ahora podemos expresar lo mismo para x': x'=(x'', c'),
donde x'' es un elemento de . Si continuamos con este proceso, llegamos a un nmero infinito de
caracteres, los cuales deben formar parte de x.
3/13
Ejercicio 6.10:
Considere la siguiente declaracin en sintaxis C:
Struct CharTree
{ char data;
Struct CharTree left, right;
};
(a) Vuelva a escribir CharTree como una unin similar a la declaracin unin CharList de la seccin 6.3.5
(b) Escriba una ecuacin de conjunto recursiva para la declaracin que hizo en el apartado (a).
(c) Describa un conjunto que sea la solucin ms pequea posible a la ecuacin que encontr en el
apartado (b).
(d) Demuestre que el conjunto que form en el apartado (c) es la solucin ms pequea posible.
(e) Vuelva a escribir todo esto como una declaracin vlida de C.
Ejercicio 6.11:
A continuacin se dan unas declaraciones en C:
Typedef struct Rec1 * Ptr1;
Typedef struct Rec2 * Ptr2;
Struct Rec1
{ int data;
Ptr2 next;
};
Struct Rec2
{ double data;
Ptr2 next;
};
Deben permitirse? Estn permitidas? Por qu S o por qu no?
Estas declaraciones de tipos son todas legales en C. Su equivalencia en Ada tambin es legal:
typeRec1;
typeRec2;
typePtr1isaccessRec1;
typePtr2isaccessRec2;
typeRec1isrecord
data:Integer;
next:Ptr2;
endrecord;
typeRec2isrecord
data:Integer;
next:Ptr1;
endrecord;
De hecho, en un tipo de nombre que se utiliza indirectamente en Ada, se puede declarar en cualquier
punto despus de su mismo alcance.
En C tampoco existen requerimientos para las estructuras de datos declaradas con anterioridad a su
uso indirecto.
Ejercicio 6.12:
(a) Cual es la diferencia en Ada entre un subtipo y tipo derivado?
(b) En Ada a qu declaracin de tipo en C es equivalente la siguiente declaracin?
Subtype New_Int Is integer;
(c) Y la siguiente declaracin?
Type New_int is new integer;
Un subtipo en Ada no es un nuevo tipo, sino que se considera siempre como parte de su tipo base.
4/13
Ejercicio 6.14:
Describa las reglas de correccin e inferencia de tipos en C para la expresin condicional: e1 ? e2 : e3.
Deben tener e2 y e3 el mismo tipo? Si son del mismo tipo, pueden tratarse de cualquier tipo?
Una regla de correccin para la expresin condicional en C requerira que e1 fuera del tipo int y que
e2 y e3 fueran de tipos equivalentes entre ellos; la inferencia de tipo de la expresin completa sera
del tipo de e2 y e3. Como siempre, las conversiones automticas con punteros y tipos numricos en
C complican seriamente la situacin. Aqu, por ejemplo, se usa la regla utilizada en Kernighan y
Ritchie [1988]:
Si el segundo y tercer operando son aritmticos, la conversin aritmtica normal produce que ambos
sean de un tipo comn, y que ste sea el tipo del resultado. Si ambos son void, o estructuras o
uniones del mismo tipo, o punteros a objetos del mismo tipo, el resultado tiene un tipo comn. Si uno
es un puntero y el otro una constante 0, el 0 se convierte en un puntero, y el resultado tiene este tipo.
Si uno es un puntero a void y el otro es otro puntero, el otro puntero se convierte en un puntero a
void, y ste es el tipo del resultado.
Ejercicio 6.15:
Suponga que usamos el cdigo de C++, que intenta evitar el uso de un static_cast para imprimir el valor
interno de true (vea el cdigo al final de la seccin 6.7).
Unin
{ int i;
Bool b;
} x;
x.b = true;
cout << x.i << endl;
El problema es que el valor bool ocupa normalmente un byte de memoria, pero un valor int ocupa 4.
Cuando, por ejemplo, realizamos la asignacin x.i = 20000, los 4 bytes de x aparecern ahora en
hexadecimal como 00004E20. Cuando asignamos x.b = true, los ltimos dos dgitos de ste valor
(20) son reemplazados por el valor interno de true (normalmente 1), y el resultado es 00004E01, o
19969 en decimal.
As, este cdigo imprimira 19969, y no 1 como cabra esperar. Por supuesto, si inicializamos primero
x.i a 0, se corregir este problema, por ello el siguiente cdigo sera ms correcto:
unin
{inti;
boolb;
}x;
x.i=0;
x.b=true;
cout<<x.i<<endl;
5/13
Ejercicio 6.18:
A continuacin, algunas declaraciones de tipo y variables en sintaxis de C:
Typedef char* Tabla1;
Typedef char* Tabla2;
Tabla1 x, y;
Tabla2 z;
Tabla2 w;
Diga qu variables son equivalentes en tipo, segn equivalencia estructural, equivalencia de nombre y
algoritmo de equivalencia actual de C. asegrese de identificar, a partir de la informacin suministrada,
aquellos casos que sean ambiguos.
Equivalencia estructural: X, Y, Z y W son equivalentes estructuralmente.
Equivalencia de nombre: X e Y son posiblemente equivalentes en nombre (con ambigedad, en Ada
no lo sera). Z y W tambin son equivalentes en nombre (sin ambigedad). De otra forma, ninguna de
las variables sera equivalente.
Puesto que C utiliza la estructura de equivalencia por punteros, todas las variables son equivalentes
bajo el punto de vista de C.
Ejercicio 6.19:
Dadas las declaraciones:
Int x[10];
Int y[5];
Son x e y equivalentes en C?
6/13
Ejercicio 6.22:
A continuacin damos varias declaraciones de tipo y de variable sen sintaxis de C:
Typedef struct
{ int x;
Char y;
} Rec1;
Typedef Rec1 Rec2;
Typedef struct
{ int x;
Char y;
} Rec3;
Rec1 a, b;
Rec2 c;
Rec3 d;
Diga qu variables son equivalentes en tipo segn equivalencia estructural, equivalencia de nombres y,
algoritmo de equivalencia actual de C. asegrese de identificar a partir de la informacin suministrada,
aquellos casos que son ambiguos.
Equivalencia estructural:
Estructuralmente a, b, c y d son equivalentes.
Equivalencia de nombres:
a y b son equivalentes en nombre.
Algoritmo de equivalencia: Las variables a, b, y c son equivalentes en C, puesto que C utiliza
equivalencia de declaracin, y las definiciones de las tres variables se refieren a la misma
declaracin de struct (Rec1). La variable d no es equivalente a las otras, puesto que viene de
una declaracin struct diferente.
Ejercicio 6.23:
En C++, la prueba de igualdad == puede aplicarse a arreglos, pero prueba algo equivocado, y no es posible
en absoluto aplicar el operador de asignaciones = a operadores. Explique las razones.
Un arreglo en C es implcitamente un puntero que apunta a la primera posicin de memoria; en otras
palabras, si a es un arreglo, entonces a es lo mismo que &a[0]. Puesto que los arreglos son
localizados por el sistema (en la pila), un arreglo es tambin una constante, y no puede ser
reasignada. Por ello, la verificacin de igualdad en C verifica la igualdad de punteros y no la igualdad
de valores.
Adems, la asignacin no se puede usar, puesto que un arreglo es una direccin de una constante.
Ejercicio 6.25:
Segn las reglas de tipos descritas en este texto, el constructor de arreglos en C no construye un tipo
nuevo; esto es, a los arreglos se les aplica equivalencia estructural. Cmo escribira un cdigo para probar
esto? (sugerencia: Podemos emplear una prueba de igualdad? Existe alguna otra forma de probar la
compatibilidad?)
La verificacin de igualdad se puede utilizar, incluso si no lo hace correctamente: siempre devuelve
falso, puesto que verifica la identidad en memoria, es decir, igualdad de punteros. Pero en este
problema no nos preocupa el resultado, slo cuando se genera un mensaje del compilador.
intx[10];
inty[5];
charz[20];
if(x==y);/*verificacincorrecta*/
if(x==z);/*verificacinincorrecta*/
Por ejemplo, el compilador Gnu C genera la siguiente advertencia en la ltima lnea del cdigo
indicado: "comparacin de distintos tipos de punteros carece de modelo". As, C utiliza la equivalencia
estructural para los arreglos.
Observe que la asignacin no se puede utilizar para probar esto, puesto que la asignacin a una
variable arreglo es ilegal por otras razones.
7/13
Note que no hay problemas de alineacin para esta arquitectura, puesto que tanto long como
float son de 4 bits. Sin embargo, el resultado en coma flotante es incorrecto.
Ejercicio 6.28:
Demuestre cmo concluye la verificacin de tipos Hindley-Mildner donde la siguiente funcin (en sintaxis
ML) toma un parmetro entero y devuelve un resultado entero (es decir, es del tipo int -> int en la
terminologa ML).
Fun factorial n = if n = 0 then 1 else n * factorial (n-1);
El rbol sintctico para esta definicin es el siguiente:
Definicin
Factorial
()
if
=
n 0
()
*
n
call
Factorial
()
Ahora, si realiza un recorrido de izquierda a derecha o de abajo arriba de este rbol, descubrir que =int
(de la comparacin de n con 0), y que =int (de la multiplicacin de n y el resultado de la llamada recursiva
a factorial).
Ejercicio 6.29:
A continuacin aparece la funcin en sintaxis de ML: fun f (g, x) = g (g (x));
(a) Qu tipo polimrfico tiene esta funcin?
8/13
Definicin
f
()*(, )
Producto
g
()
x
()
call
g call
()
g
x
()
()
Ejercicio 6.30:
Escriba una funcin swap polimrfica que intercambie los valores de dos variables del mismo tipo en C++.
template<typenameT>
voidswap(T&x,T&y)
{Tt=x;
x=y;
y=t;
}
Ejercicio 6.34:
El polimorfismo paramtrico explcito no necesariamente debe quedar restringido a un parmetro de tipo
nico. Por ejemplo, en C++ uno puede escribir:
Template <typename Primero, typename Segundo>
Struct Par
{ Primero primero;
Segundo segundo;
};
Escriba una funcin de plantilla hazPar en C++ que tome dos parmetros de tipos diferentes y devuelva un
Par que contenga los dos valores.
template <typename Primero, typename Segundo>
Par < primero, Segundo> hazPar (Primero f, Segundo s)
{Par < primero, Segundo> p;
p.primero = f; p.segundo= s;
return p;
}
Ejercicio 6.36:
Es el polimorfismo paramtrico de C++, polimorfismo let-bound? (sugerencia: Vea las funciones makepair
y makepair2 en la pgina 221)
9/13
De hecho, el polimorfismo en C++ es let-bound, puesto que cualquier argumento de una funcin
polimrfica debe ser instanciado a una funcin actual en el punto donde es llamada. Considere, por
ejemplo el siguiente cdigo:
(1)
template<typenameT>
(2)
Tid(Tx)
(3)
{returnx;}
(4)
template<typenameFirst,typenameSecond>
(5)
structPair
(6)
{Firstfirst;
(7)
Secondsecond;
(8)
};
(9)
template<typenameFirst,typenameSecond,typenameThird>
(10)
Pair<First,Second>makePair(Firstx,Secondy,Thirdf)
(11)
{Pair<First,Second>p;
(12)
p.first=f(x);p.second=f(y);
(13)
returnp;
(14)
}
(15)
intmain()
(16)
{Pair<int,char>z=makePair(1,'a',id);//dequtipoesid?
(17)
cout<<z.first<<endl;
(18)
cout<<z.second<<endl;
(19)
return0;
(20)
}
El uso del id no instanciado de la lnea 16 causa el siguiente mensaje de error generado por el
compilador Gnu C++:
No hay concordancia en la llamada a la funcin 'makePair(int, char, <tipo desconocido>)'
Ejercicio 6.37:
En C++ se presenta el problema de la verificacin de ocurrencias? Explique las razones.
El problema de la verificacin de ocurrencias no puede ocurrir en C++ porque C++ utiliza polimorfismo
paramtrico explcito, y los tipos recurrentes auto-referenciados no se pueden escribir explcitamente.
Ejercicio 6.38:
Un problema relacionado con el polimorfismo let-bound en ML es el de la recursin polimrfica, en
donde una funcin se llama a s misma en forma recursiva, pero en diferentes tipos y puntos del cdigo. Por
ejemplo, considere la siguiente funcin en ML:
Fun f x = if x = x then true else (f false);
Qu tipo tiene esta funcin en ML? ste es el tipo ms general que podra tener? Demuestre como llega
ML a esta respuesta.
ML llega al tipo fun : bool -> bool debido a la funcin f dada en el ejercicio, la cual no es de ninguna
manera el tipo ms general al que podemos llegar.
El motivo es simple: durante la verificacin de tipos, cuando el motor de la interfaz llega a la llamada
(f false), f todava tiene un tipo indeterminado, y el argumento booleano produce que el analizador
restrinja el tipo del parmetro a bool.
Ejercicio 6.44:
Qu nuevos constructores de tipos agrega C++ a los de C? Agregue stos al rbol de tipos de la figura 6.5.
C++ aade el constructor de tipo clase. Adems, C++ tiene tipos de referencia (vea la pgina 212), los
cuales difieren del tipo puntero, ya que los tipos de referencia tambin se convierten en nuevos tipos
derivados en C++. La construccin enum llega al nivel de tipo original en C++. C++ tambin provee de un
tipo bool, que es considerado como un tipo numrico. Finalmente, C++ ofrece un nuevo tipo wchar_t para
soportar caracteres unicode.
10/13
Tipos en C++
Bsicos
Derivados
void
Numrico
Entero
Sin signo
Puntero
Referencia
Arreglo
Funcin
float
Struct
Unin
Enum
Float
booleano
Con signo
char
Double
Wchar_t
int
Long double
Short int
Long int
Ejercicio 6.46:
Qu operaciones considerara necesarias para un tipo de datos de cadena? Cmo soportan los arreglos
de caracteres estas operaciones?
Operaciones tpicas para los arreglos son: longitud, asignacin, comparacin, concatenacin, extraccin de
subcadenas, posicin de un carcter, carcter de una posicin, reemplazo de caracteres en una cadena.
Los arreglos de caracteres en lenguajes como Modula-2 soportan asignaciones, comparacin, extraccin de
carcter y reemplazo de carcter. Las otras operaciones no se soportan directamente.
Concatenacin o extraccin de cadenas son particularmente problemticas debido a las restricciones que
tienen los arreglos de tamao fijo.
En un lenguaje con arreglos de tamao variable, como puede ser C o Algol 60, hay pocos problemas con las
restricciones de tamao, pero la mayor parte de las operaciones dadas no se soportan (incluyendo la
asignacin y comparacin en C).
C tiene una librera estndar de la funcin string que elimina muchos de estos problemas (pero no los de
almacenamiento).
Java tiene la clase String definida como parte del lenguaje, la cual tambin elimina muchos problemas
(excepto por el uso del == y unos pocos ms).
Ada tiene el tipo predefinido string que es equivalente a un arreglo de caracteres con tamao ilimitado. Ada
directamente soporta asignaciones, comparaciones, concatenacin y extraccin de subcadenas.
Ejercicio 6.49:
Debera estar disponible la prueba de igualdad para los tipos de punto flotante? Razone su respuesta.
La igualdad de tipos en coma flotante es problemtica porque casi siempre se implementa en hardware
como una verificacin de memoria a nivel de bit, y los valores sufren redondeos, truncamientos y otros
errores introducidos por la aritmtica en coma flotante.
Por ejemplo, el siguiente programa en C++ podra o no imprimir OK para ciertos valores de y:
#include <iostream>
using namespace std;
int main()
{ double x, y;
cin >> y;
11/13
Ejercicio 6.51:
Las reglas de conversin para una expresin aritmtica como e1 + e2 en C estn establecidas en
Kerningham y Ritchie como sigue:
En primer lugar, todos los operandos de tipo char o short son convertidos a int y todos los tipos
float son convertidos a double. Despus, si alguno de los operandos es double, el otro es
convertido a double y ste es el tipo del resultado.
Por otra parte, si alguno de los operandos es long, el otro es convertido a long y ste es el tipo del
resultado.
Por otra parte, si alguno de los operandos es unsigned, el otro es convertido a unsigned y ste es
el tipo del resultado.
Por otra parte, ambos operandos deben ser int, y ste es el tipo del resultado.
Dada la siguiente expresin en C, suponiendo que x es unsigned con valor 1, describa las conversiones de
tipo que ocurren durante la evaluacin y el tipo del valor resultante.
Cul es el valor resultante?
'0' + 1.0 * (-1 + x)
+
*
1.0
'0'
+
-1
char
int
double +
int
double
double
double double
U
12/13
int
U
+
int
U
double
int
double
int
double U
double double
U
+
int
*
double +
+
int
double
int
float +
+
*
float +
x
int
double
int
double double
U
El primer recuadro muestra el rbol correspondiente a la expresin dada, y el segundo se han sustituido los
valores de cada nodo por el tipo de datos al que corresponde.
En el tercer recuadro se ha sustituido char por int y en el cuarto recuadro float por double.
En el quinto recuadro tenemos la expresin int + unsigned por lo que se sustituye int por unsigned
asignando el resultado de la suma el tipo unsigned (sexto recuadro).
En el sptimo recuadro tenemos la expresin double + unsigned, por lo tanto cambiamos unsigned por
double y devolvemos el tipo double a la expresin (octavo recuadro).
En el noveno recuadro nos queda la expresin double + int por lo que cambiamos int por double y
devolvemos como resultado el tipo double (dcimo recuadro).
Las conversiones de tipos realizadas son:
char + float * (int + unsigned)
char + float * (unsigned + unsigned)
char + float * (unsigned)
char + float * (float)
char + float
float + float
float.
int = unsigned
(unsigned + unsigned) = unsigned
float * (unsigned) = float
float * (float) = float
char + float = float + float
float + float = float
13/13