1. Declarations and Initializations

comp.lang.c FAQ list · Question 1.1

Q: How should I decide which integer type to use?


A: If you might need large values (above 32,767 or below -32,767), use long. Otherwise, if space is very important (i.e. if there are large arrays or many structures), use short. Otherwise, use int. If well-defined overflow characteristics are important and negative values are not, or if you want to steer clear of sign-extension problems when manipulating bits or bytes, use one of the corresponding unsigned types. (Beware when mixing signed and unsigned values in expressions, though; see question 3.19.)

Although character types (especially unsigned char) can be used as ``tiny'' integers, doing so is sometimes more trouble than it's worth. The compiler will have to emit extra code to convert between char and int (making the executable larger), and unexpected sign extension can be troublesome. (Using unsigned char can help; see question 12.1 for a related problem.)

A similar space/time tradeoff applies when deciding between float and double. (Many compilers still convert all float values to double during expression evaluation.) None of the above rules apply if pointers to the variable must have a particular type.

Variables referring to certain kinds of data, such as sizes of objects in memory, can and should used predefined abstract types such as size_t.

It's often incorrectly assumed that C's types are defined to have certain, exact sizes. In fact, what's guaranteed is that:

From these values, it can be inferred that char is at least 8 bits, short int and int are at least 16 bits, and long int is at least 32 bits. (The signed and unsigned versions of each type are guaranteed to have the same size.) Under ANSI C, the maximum and minimum values for a particular machine can be found in the header file <limits.h>; here is a summary:

Base typeMinimum size (bits)Minimum value (signed)Maximum value (signed)Maximum value (unsigned)
char8-127127255
short16-32,76732,76765,535
int16-32,76732,76765,535
long32-2,147,483,6472,147,483,6474,294,967,295
(These values are the minimums guaranteed by the Standard. Many implementations allow larger values, but portable programs shouldn't depend on it.)

If for some reason you need to declare something with an exact size (usually the only good reason for doing so is when attempting to conform to some externally-imposed storage layout, but see question 20.5), be sure to encapsulate the choice behind an appropriate typedef, but see question 1.3.

If you need to manipulate huge values, larger than the guaranteed range of C's built-in types, you need an arbitrary-precision (or ``multiple precision'') arithmetic library; see question 18.15d.

References: K&R1 Sec. 2.2 p. 34
K&R2 Sec. 2.2 p. 36, Sec. A4.2 pp. 195-6, Sec. B11 p. 257
ISO Sec. 5.2.4.2.1, Sec. 6.1.2.5
H&S Secs. 5.1,5.2 pp. 110-114




comp.lang.c FAQ list · Question 1.2

Q: Why aren't the sizes of the standard types precisely defined?


A: Though C is considered relatively low-level as high-level languages go, it does take the position that the exact size of an object (i.e. in bits) is an implementation detail. (The only place where C lets you specify a size in bits is in bit-fields within structures; see questions 2.25 and 2.26.) Most programs do not need precise control over these sizes; many programs that do try to achieve this control would be better off if they didn't.

Type int is supposed to represent a machine's natural word size. It's the right type to use for most integer variables; see question 1.1 for other guidelines. See also questions 12.42 and 20.5.




comp.lang.c FAQ list · Question 1.3

Q: Since C doesn't define sizes exactly, I've been using typedefs like int16 and int32. I can then define these typedefs to be int, short, long, etc. depending on what machine I'm using. That should solve everything, right?


A: If you truly need control over exact type sizes, this is the right approach. There remain several things to be aware of:

See also questions 10.16 and 20.5.




comp.lang.c FAQ list · Question 1.4

Q: What should the 64-bit type be on a machine that can support it?


A: The new C99 Standard specifies type long long as effectively being at least 64 bits, and this type has been implemented by a number of compilers for some time. (Others have implemented extensions such as __longlong.) On the other hand, it's also appropriate to implement type short int as 16, int as 32, and long int as 64 bits, and some compilers do.

See also questions 1.3 and 18.15d.

Additional links: Part of a proposal for long long for C9X by Alan Watson and Jutta Degener, succinctly outlining the arguments.

References: C9X Sec. 5.2.4.2.1, Sec. 6.1.2.5




comp.lang.c FAQ list · Question 1.5

Q: What's wrong with this declaration?

char* p1, p2;
I get errors when I try to use p2.


A: Nothing is wrong with the declaration--except that it doesn't do what you probably want. The * in a pointer declaration is not part of the base type; it is part of the declarator containing the name being declared (see question 1.21). That is, in C, the syntax and interpretation of a declaration is not really

	type identifier ;
but rather
	base_type thing_that_gives_base_type ;
where ``thing_that_gives_base_type''--the declarator--is either a simple identifier, or a notation like *p or a[10] or f() indicating that the variable being declared is a pointer to, array of, or function returning that base_type. (Of course, more complicated declarators are possible as well.)

In the declaration as written in the question, no matter what the whitespace suggests, the base type is char and the first declarator is ``* p1'', and since the declarator contains a *, it declares p1 as a pointer-to-char. The declarator for p2, however, contains nothing but p2, so p2 is declared as a plain char, probably not what was intended. To declare two pointers within the same declaration, use

	char *p1, *p2;
Since the * is part of the declarator, it's best to use whitespace as shown; writing char* invites mistakes and confusion.

See also question 1.13.

Additional links: Bjarne Stroustrup's opinion




comp.lang.c FAQ list · Question 1.6

Q: I'm trying to declare a pointer and allocate some space for it, but it's not working. What's wrong with this code?

char *p;
*p = malloc(10);


A: The pointer you declared is p, not *p. See question 4.2.




comp.lang.c FAQ list · Question 1.7

Q: What's the best way to declare and define global variables and functions?


A: First, though there can be many declarations (and in many translation units) of a single global variable or function, there must be exactly one definition. [footnote] For global variables, the definition is the declaration that actually allocates space, and provides an initialization value, if any. For functions, the definition is the ``declaration'' that provides the function body. For example, these are declarations:

	extern int i;

	extern int f();
and these are definitions:
	int i = 0;

	int f()
	{
		return 1;
	}
(Actually, the keyword extern is optional in function declarations; see question 1.11.)

When you need to share variables or functions across several source files, you will of course want to ensure that all definitions and declarations are consistent. The best arrangement is to place each definition in some relevant .c file. Then, put an external declaration in a header (``.h'') file, and #include it wherever the declaration is needed. The .c file containing the definition should also #include the same header file, so the compiler can check that the definition matches the declarations.

This rule promotes a high degree of portability: it is consistent with the requirements of the ANSI C Standard, and is also consistent with most pre-ANSI compilers and linkers. (Unix compilers and linkers typically use a ``common model'' which allows multiple definitions, as long as at most one is initialized; this behavior is mentioned as a ``common extension'' by the ANSI Standard, no pun intended. A few very old systems might once have required an explicit initializer to distinguish a definition from an external declaration.)

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, especially since it's usually a better idea to keep global variables to a minimum.

It's not just a good idea to put global declarations in header files: if you want the compiler to be able to catch inconsistent declarations for you, you must place them in header files. In particular, never place a prototype for an external function in a .c file--if the definition of the function ever changes, it would be too easy to forget to change the prototype, and an incompatible prototype is worse than useless.

See also questions 1.24, 10.6, 17.2, and 18.8.

References: 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




comp.lang.c FAQ list · Question 1.8

Q: How can I implement opaque (abstract) data types in C?


A: See question 2.4.




comp.lang.c FAQ list · Question 1.9

Q: How can I make a sort of ``semi-global'' variable, that is, one that's private to a few functions spread across a few source files?


A: You can't do this in C. If it's impossible or inconvenient to put all the functions in the same source file, there are two usual solutions:

  1. Pick a unique prefix for the names of all functions and global variables in a library or package of related routines, and warn users of the package not to define or use any symbols with names matching that prefix other than those documented as being for public consumption. (In other words, an undocumented but otherwise global symbol with a name matching that prefix is, by convention, ``private.'')
  2. Use a name beginning with an underscore, since such names shouldn't be used by ordinary code. (See question 1.29 for more information, and for a description of the ``no man's land'' between the user and implementation namespaces.)

It may also be possible to use special linker invocations to adjust the visibility of names, but any such techniques are outside of the scope of the C language.




comp.lang.c FAQ list · Question 1.10

Q: Do all declarations for the same static function or variable have to include the storage class static?


A: The language in the Standard does not quite require this (what's most important is that the first declaration contain static), but the rules are rather intricate, and are slightly different for functions than for data objects. (There has also been a lot of historical variation in this area.) Therefore, it's safest if static appears consistently in the definition and all declarations.

Additional links: An article by Jutta Degener explaining the subtly different rules for static variables versus static functions.

References: ISO Sec. 6.1.2.2
Rationale Sec. 3.1.2.2
H&S Sec. 4.3 p. 75




comp.lang.c FAQ list · Question 1.11

Q: What does extern mean in a function declaration?


A: extern is significant only with data declarations. In function declarations, it can be used as a stylistic hint to indicate that the function's definition is probably in another source file, but there is no formal difference between

	extern int f();
and
	int f();

See also question 1.10.

References: 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




comp.lang.c FAQ list · Question 1.12

Q: What's the auto keyword good for?


A: Nothing; it's archaic. [footnote] (It's a holdover from C's typeless predecessor language B, where in the absence of keywords like int a declaration always needed a storage class.) See also question 20.37.

References: 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




comp.lang.c FAQ list · Question 1.13

Q: What's the difference between using a typedef or a #define for a user-defined type?


A: In general, typedefs are preferred, in part because they can correctly encode pointer types. For example, consider these declarations:

	typedef char *String_t;
	#define String_d char *
	String_t s1, s2;
	String_d s3, s4;
s1, s2, and s3 are all declared as char *, but s4 is declared as a char, which is probably not the intention. (See also question 1.5.)

#defines do have the advantage that #ifdef works on them (see also question 10.15). On the other hand, typedefs have the advantage that they obey scope rules (that is, they can be declared local to a function or block).

See also questions 1.17, 2.22, 11.11, and 15.11.

References: K&R1 Sec. 6.9 p. 141
K&R2 Sec. 6.7 pp. 146-7
CT&P Sec. 6.4 pp. 83-4




comp.lang.c FAQ list · Question 1.14

Q: I can't seem to define a linked list successfully. I tried

	typedef struct {
		char *item;
		NODEPTR next;
	} *NODEPTR;
but the compiler gave me error messages. Can't a structure in C contain a pointer to itself?


A: Structures in C can certainly contain pointers to themselves; the discussion and example in section 6.5 of K&R make this clear.

The problem with this example is the typedef. A typedef defines a new name for a type, and in simpler cases [footnote] you can define a new structure type and a typedef for it at the same time, but not in this case. A typedef declaration can not be used until it is defined, and in the fragment above, it is not yet defined at the point where the next field is declared.

To fix this code, first give the structure a tag (e.g. ``struct node''). Then, declare the next field as a simple struct node *, or disentangle the typedef declaration from the structure definition, or both. One corrected version would be:

	typedef struct node {
		char *item;
		struct node *next;
	} *NODEPTR;
You could also precede the struct declaration with the typedef, in which case you could use the NODEPTR typedef when declaring the next field, after all:
	typedef struct node *NODEPTR;

	struct node {
		char *item;
		NODEPTR next;
	};
(In this case, you declare a new tyedef name involving struct node even though struct node has not been completely defined yet; this you're allowed to do.[footnote] )

Finally, here is a rearrangement incorporating both suggestions:

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

	typedef struct node *NODEPTR;

(It's a matter of style which method to prefer; see section 17.)

See also questions 1.15 and 2.1.

References: 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




comp.lang.c FAQ list · Question 1.15

Q: How can I define a pair of mutually referential structures? I tried

	typedef struct {
		int afield;
		BPTR bpointer;
	} *APTR;

	typedef struct {
		int bfield;
		APTR apointer;
	} *BPTR;
but the compiler doesn't know about BPTR when it is used in the first structure declaration.


A: As in question 1.14, the problem lies not in the structures or the pointers but the typedefs. First, give the two structures tags, and define the link pointers without using typedefs:

	struct a {
		int afield;
		struct b *bpointer;
	};

	struct b {
		int bfield;
		struct a *apointer;
	};
The compiler can accept the field declaration struct b *bpointer within struct a, even though it has not yet heard of struct b. (struct b is ``incomplete'' at that point.) Occasionally it is necessary to precede this couplet with the empty declaration
	struct b;
to mask the declarations (if in an inner scope) from a different struct b in an outer scope.

After declaring the two structures using struct tags, you can then declare the typedefs separately:

	typedef struct a *APTR;
	typedef struct b *BPTR;

Alternatively, you can define the typedefs before the struct definitions[footnote] , in which case you can use them when declaring the link pointer fields:

	typedef struct a *APTR;
	typedef struct b *BPTR;

	struct a {
		int afield;
		BPTR bpointer;
	};

	struct b {
		int bfield;
		APTR apointer;
	};

See also question 1.14.

References: K&R2 Sec. 6.5 p. 140
ISO Sec. 6.5.2.3
H&S Sec. 5.6.1 p. 132




comp.lang.c FAQ list · Question 1.16

Q: What's the difference between these two declarations?

	struct x1 { ... };
	typedef struct { ... } x2;


A: See question 2.1.




comp.lang.c FAQ list · Question 1.17

Q: What does

typedef int (*funcptr)();
mean?


A: It defines a typedef, funcptr, for a pointer to a function (taking unspecified arguments) returning an int. It can be used to declare one or more pointers to functions:

	funcptr pf1, pf2;
which is equivalent to the more verbose, and perhaps harder to understand
	int (*pf1)(), (*pf2)();
See also questions 1.21, 4.12, and 15.11.

References: K&R1 Sec. 6.9 p. 141
K&R2 Sec. 6.7 p. 147




comp.lang.c FAQ list · Question 1.18

Q: I've got the declarations

	typedef char *charp;
	const charp p;
Why is p turning out const, instead of the characters pointed to?


A: See question 11.11.




comp.lang.c FAQ list · Question 1.19

Q: I don't understand why I can't use const values in initializers and array dimensions, as in

	const int n = 5;
	int a[n];


A: See question 11.8.




comp.lang.c FAQ list · Question 1.20

Q: What's the difference between const char *p, char const *p, and char * const p?


A: See questions 11.9 and 1.21.




comp.lang.c FAQ list · Question 1.20b

Q: What does it mean for a function parameter to be const? What do the two const's in

	int f(const * const p)
mean?


A: In

	int f(const * const p)
the first of the two const's is perfectly appropriate and quite useful; many functions declare parameters which are pointers to const data, and doing so documents (and tends to enforce) the function's promise that it won't modify the pointed-to data in the caller. The second const, on the other hand, is almost useless; all it says is that the function won't alter its own copy of the pointer, even though it wouldn't cause the caller or the function any problems if it did, nor is this anything the caller should care about in any case. The situation is the same as if a function declared an ordinary (non-pointer) parameter as const:
	int f2(const int x)
This says that nowhere in the body of f2() will the function assign a different value to x. (Compilers should try to enforce this promise, too.) But assigning a different value to x wouldn't affect the value that the caller had passed (because C always uses call-by-value), so it's an unimportant guarantee, and in fact a pretty useless one, because what does the function gain by promising (to itself, since it's the only one that could care) whether it will or won't be modifying in the passed-in copy of the value?


comp.lang.c FAQ list · Question 1.21

Q: How do I construct declarations of complicated types such as ``array of N pointers to functions returning pointers to functions returning pointers to char'', or figure out what similarly complicated declarations mean?


A: The first part of this question can be answered in at least three ways:

  1. char *(*(*a[N])())();
  2. Build the declaration up incrementally, using typedefs:
    	typedef char *pc;	/* pointer to char */
    	typedef pc fpc();	/* function returning pointer to char */
    	typedef fpc *pfpc;	/* pointer to above */
    	typedef pfpc fpfpc();	/* function returning... */
    	typedef fpfpc *pfpfpc;	/* pointer to... */
    	pfpfpc a[N];		/* array of... */
    
  3. Use the cdecl program, which turns English into C and vice versa. You provide a longhand description of the type you want, and cdecl responds with the equivalent C declaration:
    	cdecl> declare a as array of pointer to function returning
    		pointer to function returning pointer to char
    
    	char *(*(*a[])())()
    
    cdecl can also explain complicated declarations (you give it a complicated declaration and it responds with an English description), help with casts, and indicate which set of parentheses the parameters go in (for complicated function definitions, like the one above). See question 18.1.

C's declarations can be confusing because they come in two parts: a base type, and a declarator which contains the identifier or name being declared, perhaps along with *'s and []'s and ()'s saying whether the name is a pointer to, array of, or function returning the base type, or some combination.[footnote] For example, in

	char *pc;
the base type is char, the identifier is pc, and the declarator is *pc; this tells us that *pc is a char (this is what ``declaration mimics use'' means).

One way to make sense of complicated C declarations is by reading them ``inside out,'' remembering that [] and () bind more tightly than *. For example, given

	char *(*pfpc)();
we can see that pfpc is a pointer (the inner *) to a function (the ()) to a pointer (the outer *) to char. When we later use pfpc, the expression *(*pfpc)() (the value pointed to by the return value of a function pointed to by pfpc) will be a char.

Another way of analyzing these declarations is to decompose the declarator while composing the description, maintaining the ``declaration mimics use'' relationship:

	*(*pfpc)()	is a	char
	(*pfpc)()	is a	pointer to char
	(*pfpc)	is a	function returning pointer to char
	pfpc	is a	pointer to function returning pointer to char

If you'd like to make things clearer when declaring complicated types like these, you can make the analysis explicit by using a chain of typedefs as in option 2 above.

The pointer-to-function declarations in the examples above have not included parameter type information. When the parameters have complicated types, declarations can really get messy. (Modern versions of cdecl can help here, too.)

Additional links:

A message of mine explaining the difference between array-of-pointer vs. pointer-to-array declarations

David Anderson's ``Clockwise/Spiral Rule''

References: 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




comp.lang.c FAQ list · Question 1.22

Q: 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, each of which returns a pointer to the function for the next state. But I can't find a way to declare the functions--I seem to need a function returning a pointer to a function returning a pointer to a function returning a pointer to a function..., ad infinitum.


A: You can't quite do it directly. One way is to have the function return a generic function pointer (see question 4.13), with some judicious casts to adjust the types as the pointers are passed around:

typedef int (*funcptr)();	  /* generic function pointer */
typedef funcptr (*ptrfuncptr)();  /* ptr to fcn returning g.f.p. */

funcptr start(), stop();
funcptr state1(), state2(), state3();

void statemachine()
{
	ptrfuncptr state = start;

	while(state != stop)
		state = (ptrfuncptr)(*state)();
}

funcptr start()
{
	return (funcptr)state1;
}
(The second ptrfuncptr typedef hides some particularly dark syntax; without it, the state variable would have to be declared as funcptr (*state)() and the call would contain a bewildering cast of the form (funcptr (*)())(*state)().)

Another way (sugested by Paul Eggert, Eugene Ressler, Chris Volpe, and perhaps others) is to have each function return a structure containing only a pointer to a function returning that structure:

struct functhunk {
	struct functhunk (*func)();
};

struct functhunk start(), stop();
struct functhunk state1(), state2(), state3();

void statemachine()
{
	struct functhunk state = {start};

	while(state.func != stop)
		state = (*state.func)();
}

struct functhunk start()
{
	struct functhunk ret;
	ret.func = state1;
	return ret;
}
(Note that these examples use the older, explicit style of calling via function pointers; see question 4.12. See also question 1.17.)


comp.lang.c FAQ list · Question 1.23

Q: Can I declare a local array (or parameter array) of a size matching a passed-in array, or set by another parameter?


A: Historically, you couldn't, but in C99 (and in some pre-C99 compilers with extensions) you can. See questions 6.15 and 6.19.




comp.lang.c FAQ list · Question 1.24

Q: I have an extern array which is defined in one file, and used in another:

file1.c:			file2.c:

int array[] = {1, 2, 3};	extern int array[];
Why doesn't sizeof work on array in file2.c?


A: An extern array of unspecified size is an incomplete type; you cannot apply sizeof to it. sizeof operates at compile time, and there is no way for it to learn the size of an array which is defined in another file.

You have three options:

  1. Declare a companion variable, containing the size of the array, defined and initialized (with sizeof) in the same source file where the array is defined:
    file1.c:			file2.c:
    
    int array[] = {1, 2, 3};	extern int array[];
    int arraysz = sizeof(array);	extern int arraysz;
    
    (See also question 6.23.)
  2. #define a manifest constant for the size so that it can be used consistently in the definition and the extern declaration:
    file1.h:
    
    #define ARRAYSZ 3
    extern int array[ARRAYSZ];
    
    file1.c:			file2.c:
    
    #include "file1.h"		#include "file1.h"
    int array[ARRAYSZ];
    
  3. Use some sentinel value (typically 0, -1, or NULL) in the array's last element, so that code can determine the end without an explicit size indication:
    file1.c:			file2.c:
    
    int array[] = {1, 2, 3, -1};	extern int array[];
    
(Obviously, the choice will depend to some extent on whether the array was already being initialized; if it was, option 2 is poor.)

See also question 6.21.

References: H&S Sec. 7.5.2 p. 195




comp.lang.c FAQ list · Question 1.25

Q: My compiler is complaining about an invalid redeclaration of a function, but I only define it once and call it once.


A: Functions which are called without a declaration in scope, perhaps because the first call precedes the function's definition, are assumed to be declared as if by:

	extern int f();
That is, an undeclared function is assumed to return int, and to accept an unspecified number of arguments (though there must be a fixed number of them and none may be ``narrow''). If the function is later defined otherwise, the compiler complains about the discrepancy. Functions returning other than int, or accepting any ``narrow'' arguments, or accepting a variable number of arguments, must all be declared before they are called. (And it's by all means safest to declare all functions, so that function prototypes can check that arguments are passed correctly.)

Another possible source of this problem is that the function has the same name as another one declared in some header file.

See also questions 11.3 and 15.1.

References: 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




comp.lang.c FAQ list · Question 1.25b

Q: What's the right declaration for main?
Is void main() correct?


A: See questions 11.12a through 11.15. (But no, it's not correct.)




comp.lang.c FAQ list · Question 1.26

Q: My compiler is complaining about mismatched function prototypes which look fine to me.


A: See question 11.3.




comp.lang.c FAQ list · Question 1.27

Q: I'm getting strange syntax errors on the very first declaration in a file, but it looks fine.


A: See question 10.9.




comp.lang.c FAQ list · Question 1.28

Q: My compiler isn't letting me declare a big array like

double array[256][256];


A: See question 19.23, and maybe 7.16.




comp.lang.c FAQ list · Question 1.29

Q: How can I determine which identifiers are safe for me to use and which are reserved?


A: Namespace management can be a sticky issue. The problem--which isn't always obvious--is that you don't want to pick identifiers already in use by the implementation, such that you get ``multiply defined'' errors or--even worse--quietly replace one of the implementation's symbols and break everything. You also want some guarantee that later releases won't usurp names you're legitimately using. [footnote] (Few things are more frustrating than taking a debugged, working, production program, recompiling it under a new release of a compiler, and having the build fail due to namespace or other problems.) Therefore, the ANSI/ISO C Standard contains rather elaborate definitions carving out distinct namespace subsets for the user and the implementation.

To make sense of ANSI's rules, and before we can say whether a given identifier is reserved, we must understand three attributes of the identifier: its scope, namespace, and linkage.

There are four kinds of scope (regions over which an identifier's declaration is in effect) in C: function, file, block, and prototype. (The fourth one exists only in the parameter lists of function prototype declarations; see also question 11.5.)

There are four different kinds of namespaces, for:

Another set of names (though not termed a ``namespace'' by the Standard) consists of preprocessor macros; these are all expanded before the compiler gets around to considering the four formal namespaces.

The standard defines three kinds of ``linkage'': external, internal, and none. For our purposes, external linkage means global, non-static variables and functions (across all source files), internal linkage means static variables and functions with file scope, and ``no linkage'' refers to local variables, and also things like typedef names and enumeration constants.

The rules, paraphrased from ANSI Sec. 4.1.2.1, are:

Rules 3 and 4 are additionally complicated by the fact that several sets of macro names and standard library identifiers are reserved for ``future directions'' that is, later revisions of the Standard may define new names matching certain patterns.

Here is a list of the patterns which are reserved for ``future directions'' associared with each standard header:

[TABLE GOES HERE]
(The notation [A-Z] means ``any uppercase letter''; similarly, [a-z] and [0-9] indicate lower-case letters and digits. The notation * means ``anything.'' For example, the pattern for <stdlib.h> says that all external identifiers beginning with the letters str followed by a lower-case letter are reserved.)

What do the above rules really mean? If you want to be on the safe side:

In fact, the preceding subparagraphs are overly conservative. If you wish, you may remember the following exceptions:

However, before making use of any of these exceptions, recognize that some of them are pretty risky (especially exceptions 3 and 5, since you could accidentally #include the relevant header file at a later time, perhaps through a chain of nested #include files), and others (especially the ones labeled 1,2) represent sort of a ``no man's land'' between the user namespaces and the namespaces reserved to the implementation.

One reason for providing these exceptions is to allow the implementors of various add-in libraries a way to declare their own internal or ``hidden'' identifiers. If you make use of any of the exceptions, you won't clash with any identifiers defined by the Standard, but you might clash with something defined by a third-party library you're using. (If, on the other hand, you're the one who's implementing an add-on library, you're welcome to make use of them, if necessary, and if you're careful.)

(It is generally safe to make use of exception 4 to give function parameters or local variables names matching standard library routines or ``future directions'' patterns. For example, ``string'' is a common--and legal--name for a parameter or local variable.)

Additional links: Stan Brown's comprehensive list of reserved identifiers

References: ISO Sec. 6.1.2.1, Sec. 6.1.2.2, Sec. 6.1.2.3, Sec. 7.1.3, Sec. 7.13
Rationale Sec. 4.1.2.1
H&S Sec. 2.5 pp. 21-3, Sec. 4.2.1 p. 67, Sec. 4.2.4 pp. 69-70, Sec. 4.2.7 p. 78, Sec. 10.1 p. 284




comp.lang.c FAQ list · Question 1.30

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


A: Uninitialized variables with static duration (that is, those declared outside of functions, and those declared with the storage class static), are guaranteed to start out as zero, just as if the programmer had typed ``= 0'' or ``= {0}''. Therefore, such variables are implicitly initialized to the null pointer (of the correct type; see also section 5) if they are pointers, and to 0.0 if they are floating-point. [footnote]

Variables with automatic duration (i.e. local variables without the static storage class) start out containing garbage, unless they are explicitly initialized. (Nothing useful can be predicted about the garbage.) If they do have initializers, they are initialized each time the function is called (or, for variables local to inner blocks, each time the block is entered at the top[footnote] ).

These rules do apply to arrays and structures (termed aggregates); arrays and structures are considered ``variables'' as far as initialization is concerned. When an automatic array or structure has a partial initializer, the remainder is initialized to 0, just as for statics. [footnote] See also question 1.31.

Finally, dynamically-allocated memory obtained with malloc and realloc is likely to contain garbage, and must be initialized by the calling program, as appropriate. Memory obtained with calloc is all-bits-0, but this is not necessarily useful for pointer or floating-point values (see question 7.31, and section 5).

References: K&R1 Sec. 4.9 pp. 82-4
K&R2 Sec. 4.9 pp. 85-86
ISO Sec. 6.5.7, Sec. 7.10.3.1, Sec. 7.10.5.3
H&S Sec. 4.2.8 pp. 72-3, Sec. 4.6 pp. 92-3, Sec. 4.6.2 pp. 94-5, Sec. 4.6.3 p. 96, Sec. 16.1 p. 386




comp.lang.c FAQ list · Question 1.31

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

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


A: Perhaps you have an old, pre-ANSI compiler, which doesn't allow initialization of ``automatic aggregates'' (i.e. non-static local arrays, structures, or unions). You have four possible workarounds:

  1. If the array won't be written to or if you won't need a fresh copy during any subsequent calls, you can declare it static (or perhaps make it global).
  2. If the array won't be written to, you could replace it with a pointer:
    	f()
    	{
    		char *a = "Hello, world!";
    	}
    
    You can always initialize local char * variables to point to string literals (but see question 1.32).
  3. If neither of the above conditions hold, you'll have to initialize the array by hand with strcpy when the function is called:
    	f()
    	{
    		char a[14];
    		strcpy(a, "Hello, world!");
    	}
    
  4. Get an ANSI-compatible compiler.

See also question 11.29a.




comp.lang.c FAQ list · Question 1.31b

Q: What's wrong with this initialization?

char *p = malloc(10);
My compiler is complaining about an ``invalid initializer'', or something.


A: Is the declaration of a static or non-local variable? Function calls are allowed in initializers only for automatic variables (that is, for local, non-static variables).




comp.lang.c FAQ list · Question 1.32

Q: 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].


A: A string literal (the formal term for a double-quoted string in C source) can be used in two slightly different ways:

  1. As the initializer for an array of char, as in the declaration of char a[] , it specifies the initial values of the characters in that array (and, if necessary, its size).
  2. Anywhere else, it turns into an unnamed, static array of characters, and this unnamed array may be stored in read-only memory, and which therefore cannot necessarily be modified. In an expression context, the array is converted at once to a pointer, as usual (see section 6), so the second declaration initializes p to point to the unnamed array's first element.

Some compilers have a switch controlling whether string literals are writable or not (for compiling old code), and some may have options to cause string literals to be formally treated as arrays of const char (for better error catching).

See also questions 1.31, 6.1, 6.2, 6.8, and 11.8b.

References: K&R2 Sec. 5.5 p. 104
ISO Sec. 6.1.4, Sec. 6.5.7
Rationale Sec. 3.1.4
H&S Sec. 2.7.4 pp. 31-2




comp.lang.c FAQ list · Question 1.33

Q: Is char a[3] = "abc"; legal?


A: Yes. See question 11.22.




comp.lang.c FAQ list · Question 1.34

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


A: Use something like

extern int func();
int (*fp)() = func;

When the name of a function appears in an expression, it ``decays'' into a pointer (that is, it has its address implicitly taken), much as an array name does.

A prior, explicit declaration for the function (perhaps in a header file) is normally needed, as shown. The implicit external function declaration that can occur when a function is called does not help when a function name's only use is for its value.

See also questions 1.25 and 4.12.




comp.lang.c FAQ list · Question 1.35

Q: Can I initialize unions?


A: See question 2.20.





Read sequentially: prev next up



about this FAQ list   about eskimo   search   feedback   copyright

Hosted by Eskimo North