/

Declaraciones e inicializaciones


   Inicio > FAQ C > Declaraciones e inicializaciones


1.1: ¿Cómo se decide qué tipo de enteros usar?

R: Si necesitas valores grandes (por encima de 32.767 o por debajo de -32.767), usa el tipo long. En caso contrario, si el espacio es muy importante (v.g. si hay grandes arrays o muchas estructuras), usa el tiposhort. En otro caso, usa el tipo int. Si evitar el overflow es importante y los valores negativos no lo son, o si quieres olvidarte de problemas con los signos al manipular bits o bytes, usa los correspondientes tipos unsigned. (Ten cuidado al mezclar valores con singo y sin signo en expresiones).

Aunque los tipos carácter (especialmente unsigned char) pueden ser usados como "pequeños" enteros, hacer esto a veces tiene más inconvenientes que ventajas debido a y al aumento del tamaño del código. ( consulta la sección 12.1 para ver un problema relacionado).

1.4: ¿Cómo debe ser el tipo de 64 bits en una máquina que lo admita?

R: La próxima revisión del estardar C (C9X) espacifica que el tipo long long debe ser como mínimo de 64 bits, y este tipo ha sido implementado por un gran número de compiladores desde hace ya tiempo (otros han implementado extensiones tales como __longlong). Por otra parte, no hay ninguna razón teórica por la que un compilador no pudiera implementar el tipo short int como 16, int como 32, y long int como 64 bits, y algunos compiladores optan por esta opción.

Ver también la pregunta 18.15d.

Referencias: C9X Sec. 5.2.4.2.1, Sec. 6.1.2.5.

1.7: ¿Cuál es la mejor forma de declarar y definir variables globales y funciones?

R: Aunque puede haber varias "declaraciones" de una misma variable o función "global" (hablando estrictamente, "externa"), debe haber una única "definición". (La definición es la declaración que reserva espacio y establece un valor inicial, si es que hay alguno). La mejor forma de hacerlo es colocar cada definición en algún fichero .c relevante, con una declaración externa en un fichero de encabezamiento (.h), que será incluido (con #include) allá donde la declaración se necesite. El fichero .c que contiene la definición tambíen debería incluir (#include) el fichero de encabezamiento, para que el compilador pueda comprobar que la definición concuerda con las declaraciones.

Esta regla proporciona un gran grado de portabilidad: es consistente con los requierimientos del ANSI C Estándar, y también con la mayoría de los compiladores y enlazadores (linkers) pre-ANSI. (Los compiladores y enlazadores Unix usan normalmente un "modelo común" que permite múltiples definiciones, siempre y cuando se inicialice uno como máximo; este comportamiento es mencionado en el ANSI C Estandar como "extensión común". Unos pocos y extraños sistemas puede que requieran un inicializador para distinguir una definición de una declaración externa.

It is possible to use preprocessor tricks to arrange that a line like DEFINE(int, i); need only be entered once in one header file, and turned into a definition or a declaration depending on the setting of some macro, but it's not clear if this is worth the trouble. It's especially important to put global declarations in header files if you want the compiler to catch inconsistent declarations for you. In particular, never place a prototype for an external function in a .c file: it wouldn't generally be checked for consistency with the definition, and an incompatible prototype is worse than useless. Ver también las preguntas 10.6 y 18.8. Referencias: K&R1 Sec. 4.5 pp. 76-7; K&R2 Sec. 4.4 pp. 80-1; ISO Sec. 6.1.2.2, Sec. 6.7, Sec. 6.7.2, Sec. G.5.11; Rationale Sec. 3.1.2.2; H&S Sec. 4.8 pp. 101-104, Sec. 9.2.3 p. 267; CT&P Sec. 4.2 pp. 54-56.

1.11: ¿Qué significa extern en la declaración de una función?

R: Puede ser usado como una pista para indicar que la definición de la función está probablemente en otro fichero fuente, pero no hay ninguna diferencia formal entre:

extern int f();

y

int f();

Referencias: ISO Sec. 6.1.2.2, Sec. 6.5.1; Rationale Sec. 3.1.2.2; H&S Secs. 4.3,4.3.1 pp. 75-6.-

1.12: Para qué sirve la palabra clave 'auto'

Para nada, está obsoleta. Ver pregunta 20.37.

Referencias: K&R1 Sec. A8.1 p. 193; ISO Sec. 6.1.2.4, Sec. 6.5.1; H&S Sec. 4.3 p. 75, Sec. 4.3.1 p. 76.

1.14: No consigo definir una lista enlazada con éxito...

He probado con

 	typedef struct {
 	    char *item;
 	    NODEPTR next;
 	} *NODEPTR;
 

Pero el compilador me da mensajes de error. ¿Acaso no puede una estructura en C contener un puntero a si misma?

R: Por supuesto que sí pueden contener punteros a sí mismas; Los comentarios y el ejemplo de la sección 6.5 del libro de K&R lo dejan claro. El problema con este ejemplo es que el typedef no ha sido definido en el punto dondese declara el campo "next". Para arreglar este código, primero etiqueta a la estructura como "struct node". Luego declara el campo "next" como "struct node *", o libra a la declaración typedef de la definición de la estructura, o ambos. Una posible forma sería:

 	struct node {
 	   char *item;
 	   struct node *next;
 	};
 
 	typedef struct node *NODEPTR;
 

Y hay por lo menos otras tres formas equivalentes de hacerlo.

Un problema similar, con una solución similar, puede surgir cuando se intenta declara un par de estructuras typedef que hacen referencia la una a la otra.

Ver pregunta 2.1.

Referencias: K&R1 Sec. 6.5 p. 101; K&R2 Sec. 6.5 p. 139; ISO Sec. 6.5.2, Sec. 6.5.2.3; H&S Sec. 5.6.1 pp. 132-3.

1.21: ¿Como declaro un array de N punteros a funciones que devuelven punteros a funciones que a su vez devuelven punteros a carácter?

R: La primera parte de esta pregunta puede responderse al menos de tres formas:

1.- char *(*(*a[N])())();

Construir la declaración incrementalmente usando typedefs:

 	typedef char *pc;	/* puntero a char */
 	typedef pc fpc();	/* función que devuelve un puntero a char */
 	typedef fpc *pfpc;	/* puntero al tipo anterior */
 	typedef pfpc fpfpc();	/* función que devuelve... */
 	typedef fpfpc *pfpfpc;	/* puntero a... */
 	pfpfpc a[N];		/* array de... */
 

3.- Usando el programa cdecl, que traduce del inglés al C y viceversa:

 		cdecl> declare a as array of pointer to function returning
 			pointer to function returning pointer to char
 		char *(*(*a[])())()
 

cdecl también puede explicar declaraciones complicadas, ayudar con los moldes, e indicar en que par de paréntesis van los argumentos (en caso de definiciones de funiones complicadas, como el ejemplo anterior). Ver pregunta 18.1.

Los ejemplos anteriores de punteros a funciones no incluyen información sobre los parámetros. Cuando los parámetros tienen tipos complicados, las declaraciones pueden volverse *realmente* confusas (Las versiones más modernas de cdecl pueden ayudar en esta tarea).

Referencias: K&R2 Sec. 5.12 p. 122; ISO Sec. 6.5ff (esp. Sec. 6.5.4); H&S Sec. 4.5 pp. 85-92, Sec. 5.10.1 pp. 149-50.

1.22: How can I declare a function that can return a pointer to a function of the same type? I'm building a state machine with one function for each state

R: You can't quite do it directly. Either have the function return a generic function pointer, with some judicious casts to adjust the types as the pointers are passed around; or have it return a structure containing only a pointer to a function returning that structure.

1.25: Mi compilador se queja de una redeclaración inválida (invalid redeclaration) de una función

R: Las funciones a las que se llama sin haberlas declarado (quizá porque la primera llamada a la función precede a la definición de la función) se las supone declaradas como funciones que devuelven int (y sin ningún argumento), lo que lleva a discrepancias si la función está definida más tarde (y es diferente de lo supuesto).

Otra posible causa de este problema es que la función tenga el mismo nombre que otra función declarada en algún otro fichero de encabezamiento (header file).

Ver también las preguntas 11.3 y 15.1.

Referencias: K&R1 Sec. 4.2 p. 70; K&R2 Sec. 4.2 p. 72; ISO Sec. 6.3.2.2; H&S Sec. 4.7 p. 101.

1.25b: ¿Cuál es la forma correcta de declarar main()? ¿Es correcta la declaración void main()?

R: Ver respuestas 11.12a - 11.15 (pero no, no es correcta).


1.30: What am I allowed to assume about the initial values of variables which are not explicitly initialized? If global variables start out as "zero", is that good enough for null pointers and floating-point zeroes?

1.31: This code, straight out of a book, isn't compiling:

 		int f()
 		{
 			char a[] = "Hello, world!";
 		}
 

1.31b: What's wrong with this initialization?

 		char *p = malloc(10);
 

My compiler is complaining about an "invalid initializer", or something.

1.32: What is the difference between these initializations?

 		char a[] = "string literal";
 		char *p  = "string literal";
 

My program crashes if I try to assign a new value to p[i].

1.34: I finally figured out the syntax for declaring pointers to functions, but now how do I initialize one?

 

Recomiéndanos

Te gusta esta web? habla de nosotros a tus amigos.


Colabora!

Hay muchas formas de colaborar con nosotros.


Consigue el CD "El Rincón del C"



Contacta con nosotros

Subir

© Gorka Urrutia 1999-2001.