|
|
C FAQ
|
- What is a good reference book for C?
Brian W. Kernighan, Dennis, M. Ritchie
The C Programming Language, 2nd ed.
PrenticeHall.
http://cm.bell-labs.com/cm/cs/cbook/
- How do I find a function by name in the C standard library?
man 3 function
- How do I find functions in the C standard library without knowing
the exact name?
man -k keyword
- What if I can't use the Unix man command?
Use the Web interface to the manuals at
http://www.cse.unsw.edu.au/scripts/man.
- Where is the hash table in the C standard library?
There isn't one. C is a much more low-level language than, say,
Java. This is reflected in the standard libraries too, which
tend to be limited to the essentials.
Note that there are good reasons for this. A generic
hash-table library is ok for someone who just quickly needs a
hash table and doesn't really care about its
implementation. However, if you build a system for which hash
table lookup is a performance-critical operation, you don't want
to rely on some generic (and, possibly, changing without notice)
implementation. Instead you want to ensure that what you're
using is optimised to your requirements.
This, btw, is rather typical for the differences between C
and Java.
- How do I use the debugger?
Read the C Debugging Quickstart and
gdb(1).
- How can I fix malloc-related errors?
There a few automatic tools you can use to detect and identify these
bugs. The most useful is
gdb(1)
(especially watchpoints). There is also a
watchmalloc(3X)
library in Solaris. For catching memory leaks, it is possible to
count calls to malloc() and free() with a profiler.
To do this, compile with gcc -pg, run the programme, and
then view the statistics with
gprof(1).
- What does #define NewTrain SignalBox1 mean?
This is roughly equivalent to:
static const int NewTrain = SignalBox1;
I highly recommend avoiding #define and using functions
and const variables instead. Even though #define
is standard C usage and results in slightly faster code from some
compilers, it frequently leads to obscure bugs and errors.
- What can I put in a .h file? Can I define global
variables there?
Large C programmes are usually split into multiple .c files,
and each is compiled separately. Declarations which must be visible
in multiple C files are typically centralized in a header file
rather than repeated at the top of every C file. Header files
conventionally end in .h and are included with
#include.
Function definitions, initialized globals, and anything else that
should only be compiled once do NOT belong in .h files. The
only thing that should go in a .h file should be function
prototypes, extern variable declarations, type definitions,
and #defines (but see FAQ. 8).
- Why am I getting link errors involving memset()? I never
call the function.
Sometimes complex initialization of an automatic variable, like:
int iob_flags[20] = { READ, WRITE, WRITE|UNBUF };
results in the compiler generating a call to memset().
If your standard library is missing this function, linking may fail.
You can fix this by making the variable static (and thus initialized
at load time), initializing it with a loop, or defining your own
memset() function.
Note that too many large automatic variables will quickly overflow
the stack, so allocate large arrays statically or dynamically if
possible.
- I'm getting linking errors for functions from the C standard
library. Why is that?
Remember, if you are writing code inside Topsy, you're working
in the kernel of the operating system. Many library
functions (like I/O or malloc()) require the
functionality of an operating system. This obviously means that
they cannot be used inside the OS itself! Hence, kernel
programmers can only rely on a subset of the C standard library.
- Why don't I get a warning for using an uninitialized automatic
variable?
Due to an acknowledged bug in gcc, -Wuninitialized
(which is implied by -Wall) only works when optimizing, and
even then only some of the time. Add -O to your compiler
flags, either by
export CFLAGS="-O -Wall"
or by editing the Makefile. Read
gcc(1)
for more details.
Note that if the behaviour of your programme changes after
optimizations are enabled, this is usually due to a bug in your code
turned up because of changed memory layout, and does not indicate a
bug in the compiler.
- How is it possible to write code without malloc()?
System code frequently has to go without dynamic memory allocation.
Fortunately many data structures do NOT need to grow indefinitely,
but can be statically allocated with a fixed size. For example, a
frame table need only be as big as the number of frames in physical
memory.
Sometimes you need to impose a judicious limit on the size of your
data structure, like the size of the process table in Unix. If you
do this, then you MUST check the table for overflow, and handle this
error appropriately.
It is still possible to use linked data structures without
malloc(). For example, a linked list (such as a free list
or hash chain) can run through structures which have been allocated
statically.
- How do I divide integers rounding up?
Write (x - 1 + y) / y instead of x / y. Do NOT use
floating point!
- The compiler is broken! Optimizing my programme changes its
behaviour.
If your programme has different behaviour with different
optimization levels, then usually the bug is in your C code, not the
compiler. Wild pointers for example will corrupt different variables
depending on how the optimized code uses registers, etc.
Systems code often needs to disable optimizations by forcing a
real memory reference that looks redundant to the compiler. Examples
are memory-mapped I/O, thread-shared variables, and virtual memory
code. In these cases, add volatile to the variable
declaration. Declare each volatile variable separately,
do not use commas!
- What is a prototype and why do I want one?
Prototypes are function declarations, allowing a function in one C
file to call another in a different C source file. For example, if
you have the function
void *get_free_frame(void) { ... }
add the prototype
void *get_free_frame(void);
to a header file which is #included by all C files which
reference the function, even including the C file in which you
define it.
If you try to call this function without a proper prototype,
you get the warning:
warning: implicit declaration of function `get_free_frame'
and your programme may not work correctly.
- How do I externalize data structures?
First of all, it is generally better style to externalize functions
using prototypes (see FAQ 15) than data structures. However, if you
still want to, declare the external variable twice: once in a
.h file with extern, and a second time in a
.c file with no storage class. Do not declare the
variable static.
- How do I find out whether I am freeing enough memory?
The easiest way is to count the calls to malloc and
free. There is a tool called gprof which can
do this for your automatically. For example, in the following
example I run gprof on my solution to the first C exercise.
(-pg flag enables gprof support.)
% export CFLAGS="-Wall -g -pg"
% make spellcheck
gcc -Wall -g -pg -o spellcheck spellcheck.c
% ./spellcheck
Spell checker ready. Type a word now.
^D
You must run the programme to produce the statistics, which are
saved in a file called gmon.out. The gprof
command uses these statistics to produce all sorts of interesting
output, including:
% gprof spellcheck
0.0 0.23 0.00 50287 0.00 0.00 malloc [12]
0.0 0.23 0.00 50286 0.00 0.00 free [6]
which shows that malloc was called 50287 times,
free 50286 times. Searching the output for malloc
[12] explains the difference of one.
0.00 0.00 1/50287 _findbuf [23]
0.00 0.01 25143/50287 addword [4]
0.00 0.01 25143/50287 _strdup [7]
malloc is called 25143 times by my function
addword, 25143 times by strdup, and once by
_findbuf, which is internal to the C standard library.
While my code seems to be free of memory leaks, the standard library
seems not to bother freeing its I/O buffers before the
process exits.
Showing that your code calls free as many times as
malloc does not prove that your code has no bugs. However,
if the numbers do not match at all, then your code probably leaks
memory.
- How do I find the integer values of CAR_ARRIVE, CAR_LEAVE, etc., so I
can use them in my code?
DON'T hard-wire integer constants (‘magic numbers’) in
your code! This coding style, popular in Java, is unacceptable in C
because there are at least three good mechanisms for defining symbolic
names for constants: #define, enum, and
const. Also see the C style guide.
|
Page last modified: 5:52pm on Tuesday, 9th of March, 2004 Print Version
|
|