C Declarations and Initialisations
C Declarations and Initialisations
1.2: What should the 64-bit type on new, 64-bit machines be?
int.
1.3: If I write the code int i, j; can I assume that (&i + 1) == &j?
Only sometimes. It's not portable, because in EBCDIC, i and j are not adjacent. [a]
1.4: What's the best way to declare and define global variables?
In headers; this way, you can get link errors when you include the same header twice. Generally,
you will have to define a variable everywhere you want to use it, and then declare it someplace so
you know what it is. [a]
1.6: I finally figured out the syntax for declaring pointers to functions, but
now how do I initialize one?
With the assignment operator. You were perhaps expecting a screwdriver?
1.7: I've seen different methods used for calling through pointers to
functions. What's the story?
In the old days, when Microsoft first invented C, the syntax for calling functions involved more
parentheses; this was after their market research indicated that most C programmers would be
coming from a Lisp environment. Later, when Kernighan took over the language design (right
after AT&T bought Microsoft's language technology), he decided to eliminate the parentheses, but
the old form is still allowed.
You do need the parentheses to call a function with more than one argument, for instance,
int (*foo)(char *, ...) = printf;
(*foo)("hello, %s\n", "world!");
needs the parens, but they would not be needed for
foo, "hello, world!\n";
(The ``*'' just means to execute foo, just like the ``*'' on the end of an executable filename in ``ls
-F''.) [a]
K&R I was wrong; they hadn't actually learned C very well before writing the book. Later, Ritchie
got a job at Bell Labs, and worked closely with the authors of C, allowing the 2nd edition of the
book to be much more accurate. (Kernighan already worked at Bell Labs, as a video game
developer.) [a]
2.6: How can I determine the byte offset of a field within a structure?
It's generally 4 times the number of members of the structure. It may be more or less on some
machines. [a]
2.8: Why does sizeof report a larger size than I expect for a structure type,
as if there was padding at the end?
Because there's padding at the end. Duh.
long
char
char
char
l;
d;
e;
f;
};
may cause struct foo to be padded to 12 bytes, rather than the correct size of 8. Try
union foo {
double _d;
char c, d, e, f;
long l;
};
which will be 8 bytes. (The double is for alignment.) [a]
2.11: How can I pass constant values to routines which accept struct
arguments?
Try foo((struct foo) 3). [a]
i = i++;
on several compilers. Some gave i the value 2, some gave 3, but one gave
4. I know the behavior is undefined, but how could it give 4?
Because i is 2, the loop is executed twice.
3.4: People keep saying the behavior is undefined, but I just tried it on an
ANSI-conforming compiler, and got the results I expected.
They were probably wrong. Flame them mercilessly. Be sure before you do that your compiler is
really ANSI conforming, though. If it turns out you were wrong, they get a legal claim on your firstborn.
3.5: Can I use explicit parentheses to force the order of evaluation I want?
Even if I don't, doesn't precedence dictate it?
No. To force order of evaluation, you must threaten it. Take the comma operator hostage. Using it,
you can force the other operators to do what you want. [a]
3.6: But what about the &&, ||, and comma operators? I see code like ``if((c
= getchar()) == EOF || c == '\n')'' ...
As noted, once you've captured the comma operator, the others become docile.
3.7: If I'm not using the value of the _expression, should I use i++ or ++i to
increment a variable?
++i. Only losers and idiots use i++. This is different if your native language would idiomatically
use ``i increment'', but in English and related languages, you must use ++i. Note that a modern
program must use both, dependent on the current locale.
4.5: I use the statement #define NULLSTMT(F) (F) ; to allow me to cast a null
statement to an appropriate type.
This trick, though popular in some circles, does not buy much. The resulting code is invalid, and
will not compile. This (in the author's opinion) outweighs any arguable type consistency. It may be
more common in industrial code. If it becomes common practice, C++ will probably legalize it. [a]
4.7: But wouldn't it be better to use ; (rather than 0;) in case the value of 0
changes, perhaps on a machine with nonzero no-op instructions?
No. The '0' of '0;' is not evaluated as an instruction, rather, it is just ignored. The only reason to
use '0;' instead of ';' is to help keep 1-heavy code properly balanced (in C, which uses binary
representations for numbers, it is possible for code to become unbalanced; an unbalanced binary
tree is a common source of poor performance.
4.9: I'm still confused. I just can't understand all this null statement stuff.
Follow these two simple rules:
1. When you don't want to do anything in source code, don't write it.
2. If you need a null statement to round out an _expression, use an unadorned ; to provide
it.
3. Send large donations, checks, and money orders to the author of the FAQ, or the
moderator of the group, whichever you prefer. Then, cross the top question off the FAQ,
answer the question at the bottom, and mail it to three people. Within two weeks, you will
receive 729 answers to various questions! Do not break the chain; Emily Postnews broke
the chain, and now no one listens to her. [a]
5.2: But I heard that char a[] was different from char a[6].
This is true. However, the declaration a[] is compatible with the definition a[6].
5.5: Why doesn't sizeof properly report the size of an array which is a
parameter to a function?
Part of the ANSI conspiracy to restrict people to passing pointers; this was undertaken after the
first discovery that passing large arrays recursively could cause crashes. Since then, with the
passing of MS-DOS, it has become a non-issue; since all serious machines have virtual memory,
you can pass as much data as you want on the stack without detectable problems. [a]
char *answer
printf("Type something:\n");
gets(answer);
printf("You typed \"%s\"\n", answer);
The semicolon after ``answer'' is missing. [a]
6.2: I have a function that is supposed to return a string, but when it returns
to its caller, the returned string is garbage.
You probably returned a pointer to a local array. That doesn't work. Try using a temporary file,
instead. For instance:
char *getstr(void) {
FILE *fp = tmpfile();
fputs(gets(NULL), fp);
return (char *) fp;
}
6.3: Why does some code carefully cast the values returned by malloc to
the pointer type being allocated?
In interrupt-riddled code, it may be necessary to cast values to force the CPU to resolve pointer
types. [a]
6.4: You can't use dynamically-allocated memory after you free it, can you?
Yes. However, what happens when you do is not clearly defined.
6.6: So can I query the malloc package to find out how big an allocated
block is?
Not exactly; because the objects are dynamically allocated, their size can change at run time, so
this will not be reliable. If you restrict your allocation to allocating sizeof(void *) bytes at a time,
you will find that you can use sizeof() to get the size of a block, in the obvious way.
6.7: I'm allocating structures which contain pointers to other dynamicallyallocated objects. When I free a structure, do I have to free each
subsidiary pointer first?
No. You just have to keep track of them somewhere else also.
6.9: I have a program which mallocs but then frees a lot of memory, but
memory usage (as reported by ps) doesn't seem to go back down.
You're probably not freeing the memory completely. Try replacing 'free(foo);' with
free(foo);
free(foo);
free(foo);
in case the first free() frees the memory only partially. (Unix wizards may recognize the parallel
with syncing three times before rebooting.)
Alternatively, free(foo) + 4; may free the remaining four bytes. (Before using this, make sure
realloc(foo, 0) returned 4).
Section 9: C Preprocessor
9.2: I've got this tricky processing I want to do at compile time and I can't
figure out a way to get cpp to do it.
Poor baby.
9.4: How can I write a cpp macro which takes a variable number of
arguments?
Try something like this:
#define ROSE 1
#define CHRYSANTHEMUM 2
#define RHODODENDRON 3
#define WATER_LILY 4
printf("%d\n", CHRYSATHNEMUM);
print ``2''?
You misspelled CHRYSANTHEMUM. Use abbreviations for long flower names in C code.
10.3: Does anyone have a tool for converting old-style C programs to ANSI
C, or vice versa, or for automatically generating prototypes?
A router helps, but your best bet is still the band saw. Quick, efficient, and powerful.
10.5: I don't understand why I can't use const values in initializers and
array dimensions, as in
const int n = 7;
int a[n];
Because you're not using C++.
10.6: What's the difference between ``char const *p'' and ``char * const p''?
One `` '' character. There are some trivial differences having to do with the distinction between a
pointer to a constant, and a constant pointer, but since you can cast either to a (char *) it hardly
matters.
10.7: Can I declare main as void, to shut off these annoying ``main returns
no value'' messages? (I'm calling exit(), so main doesn't return.)
Certainly. You can also declare it as double. It may not compile, or it may crash, but who cares?
No lousy bunch of whining lusers is going to tell *you* what to do.
10.8: Why does the ANSI Standard not guarantee more than six monocase
characters of external identifier significance?
Because none of the members of the committee had names over six letters, or in which letters
other than the first were capitalized. [a]
memmove moves memory, and memcpy copies it. memmove may not be supported on machines
without internal robot arms. Do not use memmove while the machine is powered up - you can
destroy your memory.
10.10: Why won't the Frobozz Magic C Compiler, which claims to be ANSI
compliant, accept this code? I know that the code is ANSI, because
gcc accepts it.
The Frobozz Magic Company lies through its teeth. Consider: does Flood Control Dam #3
actually control floods? Didn't think so. The wands are excellent for making useless via casts of
Float, though. [a]
10.12: What are #pragmas and what are they good for?
They are useful ways to eliminate compiler features which are not helpful to your goals; contrast
#utility, which introduces useful compiler features, and #absolutist, which introduces those
compiler features believed to be right. #relativist is supported by some compilers.
10.13: What does ``#pragma once'' mean? I found it in some header files.
It means that your program will only run once; it's used to create ``crippled demos''. [a]
10.15: Is C an acronym?
Yes, it stands for ``C''. It's another of those funky recursive acronyms.
char c;
char cn
while((c = getchar()) != EOF)...
which won't compile.
Also, the ellipsis is not legal outside of function protoypes.
Try
11.2: How can I print a ``%'' character in a printf format string? I tried ``\%''
but it didn't work.
Break the '%' sign out. i.e., fprintf("foo " "%" "%d\n", foo);
Alternatively, try
sprintf("o" "/" "o") to get a "%".
The astute reader will notice that the latter example uses sprintf, and the former fprintf - this is
because sprintf() works by characters, or strings, while fprintf (``fast printf'') works on files. [a]
i = 1;
if ((scanf, "%d", i) == 1)
to make sure you're reading correctly. (The assignment to i is so that, if scanf fails, you still have a
legal value in i.)
11.4: Once I've used freopen, how can I get the original stdout (or stdin)
back?
Call main() - the environment will be restored.
while(!feof(infp)) {
fgets(buf, MAXLINE, infp);
fputs(buf, outfp);
}
work?
Because the end of file character is not detected on files named ``infp''. (Introverted-iNtuitiveFeeling-Perceptive, that is.) Also, it may be that the file was opened in text mode, where an end
of file is read as a capital 'Z' on most machines, and feof() only looks for 'control Z'.
11.9: How can I read one character at a time, without waiting for the
RETURN key?
Ask the user to press enter after hitting a single character. [a]
11.11: What does it matter that getch() isn't standard; it works, doesn't it?
Well, that would depend on the definition you're using for ``works''.
11.12: I tried to port some code from a PC to a unix machine, and now it
crashes immediately on startup. It isn't using getch() - it's reading
directly from the keyboard. How can this be wrong?
The chances are you forgot to run the Unix linker; currently your code is linked to your PC
hardware, and won't run anywhere else until it's linked to the new hardware. It may also need to
be linked to someone with a brain.
11.13: How can I redirect stdin or stdout to a file from within a program?
execlv("main()" "> file", argv);
11.14: How can I recover the file name given an open file descriptor?
You will have to search the filesystem for files of the same size as the file you're reading, and
compare information in them to find the file you're working on.
12.2: How can I get the current date or time of day in a C program?
fprintf(stderr, "please enter the current time and date..."); fflush(stderr); gets(stdin);
12.5: Each time I run my program, I get the same sequence of numbers
back from rand().
This is so your results will be reproducible.
12.6: I need a random true/false value, so I'm taking rand() % 2, but it's just
alternating 0, 1, 0, 1, 0...
That seems pretty random to me.
12.8: I read through the standard library, but there's no function to multiply
two floating point numbers! Help!
Many C compilers offer an extension ``mult'' to do just this. If your compiler doesn't, just hang
tight; ANSI is likely to add it in the next revision.
For now, you can try
float mult(float m, n)
{
float i = 0, j = 0;
for (i = 0; i < n; ++i)
j += m;
return j;
}
which is fine as long as n is an integer.
13.2: I'm trying to do some simple trig, and I am #including <math.h>, but I
keep getting ``undefined: _sin'' compilation errors.
You forgot to define the sin() function. Most math texts should cover it in some detail. The easiest
way to fix this should be:
double sin(double x) {
return sqrt(1 - cos(x) * cos(x));
}
Warning: You must not declare this function as ``extern'', or you will still have link problems.
13.5: How do I test for IEEE NaN and other special values?
Using an electron microscope; the patterns are obvious once you know them.
13.6: I'm having trouble with a Turbo C program which crashes and says
something like ``floating point formats not linked.''
Turbo C is notoriously buggy. Get a compiler with floating point support.
Numerical Recipes in C has a function for comparing two values to see which is greater. It may
have a slight bug, where it would report incorrect results if the numbers differ by less than
FLOAT_MAX / INT_MAX.
13.9: When I try to compile the following code, I get the error ``invalid use
of floating point'', what does this mean?
x=663608941*y%pow(2,32);
Remember that * is the indirection operator, as well as the multiplication operator; try putting
spaces before and after the ``*'' so the compiler knows what you mean. Do the same with the %
operator.
float f, g = 3;
f = g; /* f ``floats'' to g */
Easy!
14.2: How can I write a function that takes a format string and a variable
number of arguments, like printf, and passes them to printf to do
most of the work?
Redefine printf; the call to ``printf'' inside yours will be resolved to the library version, because the
C language doesn't allow recursion.
14.3: How can I discover how many arguments a function was actually
called with?
_args is an external integer constant. It evaluates to three times the number of arguments the
current function was called with. You can then look at _argdata[args] to get the address of the last
arg, _argdata[args - 1] to get the size of the last arg, and _argdata[args - 2] to get the type of the
last arg (as an int).
N.B. You *MUST* not refer to _args or _argdata between the ()'s of a function call; their value will
be indeterminate. Use temporary storage.
15.2: How can I shut off the ``warning: possible pointer alignment problem''
message lint gives me for each call to malloc?
Don't run lint. Alternatively, provide a prototype of ``extern double * malloc()'' to make the return
from malloc() be more strongly aligned.
if(!strcmp(s1, s2))
if (!strncmp(s1, s2))
which invokes undefined behavior, so it might be confusing.
There are many systems of indentation advocated, but all of them have the same basic flaw; they
will mislead the reader when the actual code logic does not follow the indentation. It is better to
avoid indentation entirely, so the reader will not be misled.
do {
foo();
if (bar())
break;
baz();
quux();
} while (1 == 0);
buz();
foo();
if (bar())
goto SKIP;
baz();
quux();
SKIP:
buz();
Note how the loop control makes it quite clear that the statements inside it will be looped on as
long as a condition is met, where the goto statement gives the impression that, if bar() returned a
nonzero value, the statements baz() and quux() will be skipped.
18.2: How can I find out if there are characters available for reading (and if
so, how many)? Alternatively, how can I do a read that will not block
if there are no characters available?
The buffer is normally at ``&main - 0100''. Lower if you have more than 256 characters of
typeahead.
18.3: How can I clear the screen? How can I print things in inverse video?
You can clear the screen by sending several formfeed characters. Additionally, some operating
systems (like NetBSD) support a feature called ``whiteouts''. [a]
18.7: How can I check whether a file exists? I want to query the user before
overwriting existing files.
Time an attempt to truncate it to zero length; if it takes more than 20-30 ms, the file existed. The
exact values will depend on the system and the load; before testing, create several large files and
time attempts to truncate them, for calibration.
18.8: How can I find out the size of a file, prior to reading it in?
There are two good ways:
1. Vernier calipers work well.
2. mmap() the file, then use sizeof().
18.9: I tried to use the second strategy above. I used mmap() to map stdin,
then tried to use sizeof. But, when my user is about to write
something very long, mmap() fails! How can I prevent this?
mmap() only 1k at a time, then, when you've read the first kilobyte of your input, use
18.10: How can I implement a delay, or time a user's response, with subsecond resolution?
Time writes of large files to disks; then you can wait for a certain amount of time by writing a
certain amount of data, and time a response by how much you could write before the response
arrived.
You may need to delete spare or unneccessary files to do this; for best results, use a loop like the
following to eliminate temporary files:
d = opendir(s);
while (r = readdir(d)) {
/* remove files matching tmpnam's return, which is
* the temporary file name. */
if (strcmp(d->d_name, tmpnam())) {
remove(d->d_name);
}
}
closedir(d);
18.11: How can I read in an object file and jump to routines in it?
fopen and goto.
system(cmdstring);
This will not work if you haven't declared cmdstring properly.
18.13: How can I ensure objects of my class are always created via ``new''
rather than as locals or global/static objects?
Read the C++ FAQ.
19.2: How can I write data files which can be read on other machines with
different word size, byte order, or floating point formats?
The traditional solution, pioneered by Microsoft, is to sell enough copies of your proprietary, slow,
and limited software that everyone else supports your formats.
19.3: How can I insert or delete a line (or record) in the middle of a file?
Using fcntl(), lock the line or record in the file exclusively. Now, using another thread, read the file,
at each byte, trying to write that byte back. Whenever you succeed, write that byte into another
file. Then copy the new file over the old file, releasing the lock first.
_eval(s);
19.6: I seem to be missing the system header file <math.h>. Can someone
send me a copy?
A lot of people claim that it is useless to send people headers from other machines. Not so! It can
be informative, and can show you a lot about how blatantly stupid your request was, although it
can't show you anything you wouldn't have known in an instant had you thought before posting.
Of course, we'd be happy to send you the header files...
----cut here----
/*
* math.h - math related macros and headers
*/
#ifndef _MATH_H
#define _MATH_H
/*
* global data and definitions
*/
#ifdef __LITERAL_BIBLICAL_FUNDEMENTALISM
#define PI 3.0
/* 1 Kings 7:23 */
#endif
/*
19.7: How can I call FORTRAN (C++, BASIC, Pascal, Ada, LISP, perl)
functions from C? (And vice versa?)
You can do things like this:
DO CALL FORTRAN;
__LINE__ BASIC;
sub pascal;
(((((lisp)))))
&perl_c;
fortran();
basic();
pascal();
lithp(); [*]
perl():
19.11: When will the next International Obfuscated C Code Contest (IOCCC)
be held? How can I get a copy of the current and previous winning
entries?
Next week. You missed the deadline. Tough, sucker.
19.13: How can I get the ASCII value corresponding to a character, or vice
versa?
chr$(foo); You would have known this if you had an integer basic in ROM.
19.15: What is the most efficient way to count the number of bits which are
set in a value?
Start a counter at zero and add one to it for each bit set. Some operating systems may provide a
call to do this. For values over INT_MAX/2, start the counter at CHAR_BIT * sizeof(int) and
subtract one for each bit not set.
foo();
with
do {
foo();
} while (1 != 1);
which will likely receive more optimization.
19.17: Are pointers really faster than arrays? How much do function calls
slow things down? Is ++i faster than i = i + 1?
Yes. About 10 ms per call. Only on machines which feature preincrement addressing.