Converted by f2h, my perl script to turn FAQ's into HTML. Found a bug? Please report it.
[Last modified August 26, 1996 by seebs.] [Revision: yes]
[Copyright 1995, 1996 Peter Seebach. All rights reserved, all wrongs reversed. Unauthorized duplication and distribution prohibited.]
The following post has been a hobby of mine since 1995. If you enjoy it, please consider sending a token donation to help pay for my web page, and help me fund future, similar works. (Yes, I am thinking about doing others.) Email seebs@solon.com for information.
Certain topics never (well, hardly ever) come up on this newsgroup. They are stupid questions, to which the answers are immediately obvious, but they would be more fun to talk about than these arcane details of loop control.
This article, which is posted yearly, attempts to answer these questions definitively, succinctly, and in such a way as to discourage further discussion.
1. Declarations and Initializations
2. Structures, Unions, and Enumerations
3. Expressions
4. Null Statements
5. Arrays and Pointers
6. Memory Allocation
7. Characters and Strings
8. Boolean Expressions and Variables
9. C Preprocessor
10. ANSI/ISO Standard C
11. Stdio
12. Library Functions
13. Floating Point
14. Variable-Length Argument Lists
15. Lint
16. Strange Problems
17. Style
18. System Dependencies
19. Miscellaneous
Questions marked with a leading asterisk (``*'') indicate answers I have seen given as real answers, by particularly ignorant posters in comp.lang.c.
Herewith, some infrequently-asked questions and their answers:
Use ``short'' when you need to avoid values over 32,767, ``int'' when you want to store integers, ``long'' for long numbers (more than 6 digits), and ``float'' for numbers over 4 billion.
int.
int i, j;
Only sometimes. It's not portable, because in EBCDIC, i and j are not adjacent.
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.
It refers to a variable which is not actually in your program. For instance,
main() { extern int bar; printf("%d\n", bar); return 0; }
will compile without errors because bar is declared as being external. (It won't run, though, because you never assign bar a value.)
With the assignment operator. You were perhaps expecting a screwdriver?
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''.)
Declaring vehicles.
typedef struct { char *item; NODEPTR next; } *NODEPTR;
Not exactly; it can contain a pointer to another structure of the same type. Try:
typedef struct { char *item; double *next; } NODEFAKE;
typedef struct { char *item; NODEFAKE *next; } NODEPTR;
Make sure that sizeof(NODEPTR) == sizeof(double).
This technique is called a ``backwards reference''.
long ints can be entered using hexadecimal notation; for instance,
long int foo = 07;
sets foo to hex 7.
Well, first you need to know how to declare an array of N items of type T - that's
T foo[N];
Now you need to look at how to declare a pointer to function returning something, say, an object of type S. That's like this:
S (*bar)();
Now assume that S is ``pointer to function returning pointer to char''. We get
(char *) (*)() (*bar)().
So, the whole thing turns out to be (with appropriate parentheses)
(((char)(*))((*)())(((*)((foo)))())([(N))]);
If your compiler complains, break this down into subexpressions.
To call it, just use
foo[i]();
This works because, in C, declaration reflects use, but it's one of those weird distorted mirrors.
The enum doesn't require the preprocessor.
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, where he helped develop the ``kaw'' programming language, used to simulate crows in an international chess tournament.)
The structures are put into the low part of the VGA card's VRAM. They are then removed before the next video update. This is why struct passing was not supported for a long time; VGA cards were prohibitively expensive.
If you try to pass very large structures on the stack, you may see odd screen graphics.
Compare them to what? A summer's day?
Loop with putchar. Be careful; if your machine uses signed chars by default, all of the sign bits in your structure elements will be reversed.
It's generally 4 times the number of members of the structure. It may be more or less on some machines.
foo."name" should work. You may need to overload the . operator, which, in turn, may overload your C compiler.
Because there's padding at the end. *DUH*.
Sure. What you do to eliminate the padding in structures is use unions; for intance,
struct foo { char c; long l; char d; char e; char 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.)
Depends. They may go on strike when provoked. Luckily, if your program involves air traffic control, the ISO standard guarantees that Ronald Reagan will fire any unions that go on strike, and replace them with structs, which should be close enough.
Try foo((struct foo) 3).
a[i] = i++;
You didn't declare either i or a.
int i = 7; printf("%d\n", i++ * i++);
No. The only logical answer would be 81 - two postfix ++'s are automatically converted to prefix.
int i = 2; i = i++;
Because i is 2, the loop is executed twice.
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 first-born.
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.
As noted, once you've captured the comma operator, the others become docile.
++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.
Because it is unclear whether it is shorthand for
i = 42;
or
i = (char *) "forty two";
Given the ambiguity, the standards committee decided to leave it undefined.
A null statement is an expression statement consisting solely of the terminating semicolon. The optional expression is dropped. It can be distinguished from any other statement by byte count or study of side-effects.
In ANSI C, there are six types of statements; labeled statements, compound statements, expression-statements, selection statements, iteration statements, and jump statements. All of them, except the jump and expression statments, are defined in terms of optional preceeding text, and other statements. The jump statements are never null statements. An expression statement is considered to be ``a null statement'' if the optional expression part of it has been left out. A null statement can appear on its own, or (most frequently) as the statement body of an iteration statement. These two null statements are equivalent, though neither of them is equivalent to any non-null statement. [*]
You may accidentally get a null statement by deleting the body of a non-null statement.
[*] Actually, they are functionally equivalent to a large set of non-null statements, namely, those with no side-effects. However, the FDA has yet to approve any such, as their lack of side effects is conjectured, and not clinically proven. This applies only to the ANSI standard, and not the ISO standard, as the FDA has no jurisdiction outside the U.S.
Sort of. You can use ``;'', ``0;'', or ``1;'' - they will all act like a null statement. Only the first is a ``true'' null statement (all bits zero). They are basically equivalent. Note that (void *) 0; is a null statement of type pointer to void, for instance.
No. { statement-list[opt] } is a compound statement. An empty block is not the same as a null statement, however, although it can be used in many of the same places. It's really a null block. (You can convert it with a cast, but it's not directly compatible. For instance, you can't use a null block as one of the controlling statements of a for loop.)
#define NULLSTMT(F) (F) ;
This trick, though popular in some circles, does not buy much. The resulting code is illegal, 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.
#define NULLSTMT(F) (F) 0;
This trick will likely work, but think: what does it really buy you? Mostly, it will indicate to even the most casual observer that you are shakey on the concept of null statements, making it harder for them to check your code.
No. The ``0'' of ``0;'' is not evaluated as an instruction, rather, it is just ignored. The advantages of ``;'' over ``0;'' have only to do with poor optimizers and savings of keystrokes.
No. A null pointer is a pointer where all of the address bits are zero (no matter what the segment bits are), and can be obtained by typing '(char *) (int) 0'. A null statement is not a pointer to anything. They are not interchangeable, although you can combine them to get an effectively-null statement, such as
NULL;
This does not buy you anything.
Follow these two simple rules:
The declaration extern char a[] simply matches the actual definition. The type ``array-of-type-T'' is the same as ``array-of-type-T.'' Go ahead and use extern char a[]. (For greater portability, use it in both files, not only in one of them.)
This is true. However, the declaration a[] is compatible with the definition a[6].
Very little.
Classism. We consider arrays ``second class objects''. They don't vote, and they get treated as pointers. Additionally, they're merely objects, not citizens. Marx wrote about this a lot.
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.
Cool. Someone I know says he saw Elvis in a local bar.
About the difference between alcohol and marijuana; they have different characteristics, and that's not a problem if you don't mix them too carelessly.
It was added to allow people to avoid the character constant 'f' which may not be available on some systems. (Actually, it's a side-effect of the equivalence of arrays and pointers.)
You have to use a loop. For instance, the following code reads the numbers zero through 99 into the array a.
for (i = 0; i < 100; ++i) a[i] = (scanf, ("%d", i));
Make sure to include <stdio.h>, or this may not work.
char *answer printf("Type something:\n"); gets(answer); printf("You typed \"%s\"\n", answer);
The semicolon after ``answer'' is missing.
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; }
In interrupt-riddled code, it may be necessary to cast values to force the CPU to resolve pointer types.
Yes. However, what happens when you do is not clearly defined.
Interrupt 41h. On macs, amigas, and other ``big-endian'' processors, that would be interrupt 14h; be wary of portability problems.
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.
No. You just have to keep track of them somewhere else also.
The standard does not specify an allocation scheme; the famous author the allocation scheme is based on is implementation specified. Proust is a common choice, however.
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).
The obvious way is to write a function to do the conversion. (Error checking has been omitted for brevity.)
int ctoi(char c) { static unsigned char *ary; /* initialize the array */ if (!ary) { int i; ary = malloc(UCHAR_MAX + 2); for (i = 0; i < UCHAR_MAX + 1; ++i) { ary[i] = i; } ary[UCHAR_MAX + 1] = '\0'; } if (c) { unsigned char *t; /* we have to skip the leading NUL */ t = strchr(ary + 1, c); if (!t) return 0; return t - ary; } else { /* special case for NUL character */ return 0; } }
There are various clever tricks you can use to get around writing the function, but most are too complicated for beginners.
int (*)(int, char **) makes a good boolean type. You can use ``main'' for true, and ``exit'' for false. On some compilers, you may need to cast exit() to an appropriate type.
Very good! For instance, one program I saw used
#define TRUE(x) ((x) & 0x100)
for compatability with a specific release of a FORTRAN compiler, which used 0 for .FALSE. and 256 for .TRUE. - this allowed them to change their code with every new release of the FORTRAN compiler, and kept them alert to changes. This has no relationship to the boolean or logical operators in C, which always return 0 or 1.
It is not a saffron-robed monk, pissing in the snow.
#ifdef __BIG_ENDIAN should work on all known machines; Borland defines it.
Poor baby.
#define __ALL_CPP_IDS - put this in a source file, and run it through your C preprocessor.
Try something like this:
#define add(x) (x) #define add(x, y) (x + y) #pragma induction add
#define ROSE 1 #define CHRYSANTHEMUM 2 #define RHODODENDRON 3 #define WATER_LILY 4
printf("%d\n", CHRYSATHNEMUM);
You misspelled CHRYSANTHEMUM. Use abbreviations for long flower names in C code.
A whiny bunch of lusers who haven't written as many books as Herbert Schildt.
A router helps, but your best bet is still the band saw. Quick, efficient, and powerful.
This is because ``3'' is not a legal integral constant in C - it's a string constant.
const int n = 7; int a[n];
Because you're not using C++.
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.
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.
Because none of the members of the committee had names over six letters, or in which letters other than the first were capitalized.
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.
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.
You're too big and clumsy. When you try to push the numbers together, you lose your balance. Perhaps you should get some angels from the rave over on pin 3.
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.
It means that your program will only run once; it's used to create ``crippled demos''.
There isn't really one; people just enjoy flaming over nits. (To be technical, one has a hyphen, one has a space, and one is a single word.)
Yes, it stands for ``C''. It's another of those funky recursive acronyms.
char c; while((c = getchar()) != EOF)...
You forgot to include space for the terminating NUL character, so the compiler can't find the end of c without overwriting other memory. In all probability, after the user types ``n<return>'', your code will look like
char cn while((c = getchar()) != EOF)...
which won't compile.
Also, the ellipsis is not legal outside of function protoypes.
Try
char c[2]; /* include space for terminating NUL */ while ((c = getchar()) != EOF) ;
Note the use of the null statement to absorb the NUL. (See Section 4.)
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.
You need to do this a bit differently; you should always check for the return from scanf, so try something like
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.)
Call main() - the environment will be restored.
while(!feof(infp)) { fgets(buf, MAXLINE, infp); fputs(buf, outfp); }
Because the end of file character is not detected on files named ``infp''. (Introverted-iNtuitive-Feeling-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'.
Because they're trying to spoil your fun. gets() can make an otherwise droll and predictable program a lot more exciting.
Because stdout is not a mammal.
Have you turned your monitor on? If not, try hitting the ``PrtSc'' key, which will re-enable the electron guns.
Ask the user to press enter after hitting a single character.
They've been programming more than ten years. You haven't. Draw your own conclusions. That's right! They hadn't noticed it. No doubt their compilers have it too, and its behavior is identical everywhere else in the world, also. That would explain everything.
Well, that would depend on the definition you're using for ``works''.
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.
execlv("main()" "> file", argv);
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.
PUSH THE YELLOW BUTTON. TURN THE BOLT WITH THE WRENCH. (You must have the wrench, first.)
There's frequently an itoa function. Better yet, write your own; it'll be good practice. On some implementations, (char *) x; will convert x to a string.
fprintf(stderr, "please enter the current time and date..."); fflush(stderr); gets(stdin);
Count errors in Herbert Schildt's C books. No one has detected any consistent pattern.
random(n) returns random numbers between n and INT_MAX.
This is so your results will be reproducible.
That seems pretty random to me.
So do I. Let me know if you find some.
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.
Release the bird. You will have to drop the rod to get the bird in the cage.
One of the machines is probably a Pentium. Scrap it and get a real machine.
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.
It does. It looks like the multiplication operator, but you use it more. For instance, the C way of expressing ``x squared'' is ``x*x''. ``x cubed'' would be ``x*x*x''. Easy, isn't it?
Multiply by 10. Numerical Recipies in C has a section on this, but there's reputedly a bug in their algorithm.
Using an electron microscope; the patterns are obvious once you know them.
Turbo C is notoriously buggy. Get a compiler with floating point support.
Have you tried EXAMINE STICK? The stick has a sharp point, which punctures the raft, which no longer floats. Don't bring the stick into the raft with you.
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.
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.
strcpy(string_var, float_var);
The term ``float variable'' is actually redundant; they are simply variables whose value can ``float'' during execution. For instance:
float f, g = 3;
f = g; /* f ``floats'' to g */
Easy!
By declaring it with a variable number of arguments in the prototype. Use only the arguments declared at any given time.
Redefine printf; the call to ``printf'' inside yours will be resolved to the library version, because the C language doesn't allow recursion.
_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.
printf("hello, ", "world!", '\n');
It will probably work some of the time; the number of arguments used by printf() may vary, as it is a variadic function.
Yes. There's too much lint in it. You should get a shop vac.
Don't run lint. Alternatively, provide a prototype of ``extern double * malloc()'' to make the return from malloc() be more strongly aligned.
You may wish to check your spouse's navel occasionally, especially if your spouse works for a standards committee.
Lexeme Interpreter aNd Tester.
No, it didn't.
if(!strcmp(s1, s2))
Not really; it's too similar to
if (!strncmp(s1, s2))
which invokes undefined behavior, so it might be confusing.
volatile int True_Tester = 3; #define TRUE (!True_Tester == !True_Tester) #define FALSE ((!TRUE) != (!TRUE))
#define STR_DISSIMILAR(x, y) (strcmp((x), (y)) != FALSE)
Very impressive. The volatile int type assures that even seemingly redundant calculations involving True_Tester will be performed, making sure that if the compiler's ANSI-compliant values of 0 for false and 1 for true vary during runtime, your program will detect it - and producing meaningful error messages if this change occurs during a boolean computation! Similarly, the STR_DISSIMILAR macro allows you to make quite clear what the real effects of strcmp() are.
However, you must be careful; if this code is included twice, it may produce errors, due to the multiple definitions of the ``True_Tester'' variable. You may wish to declare it ``extern'' (See Question 1.5.)
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.
Yes.
Any loop control construct can be written with gotos; similarly, any goto can be emulated by some loop control constructs and additional logic.
However, gotos are unclean. For instance, compare the following two code segments:
do { foo(); foo(); if (bar()) if (bar()) goto SKIP; break; baz(); baz(); quux(); quux(); } while (1 == 0); SKIP: buz(); 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.
White space is a racist, segregational term. Implicitly, ``dark'' or ``colored'' space (i.e., the '_' character) is not good enough to separate tokens. More interestingly, the white space characters keep the other tokens apart. They say it's for parsing, but there's ample evidence the goal of white space is to keep the other characters from ``taking over'' the program. This is disguised by the description of C as ``white space insensitive'' - a simple ploy for sympathy.
Try 'stty eol ^M' to wait for a carriage return.
The buffer is normally at ``&main - 0100''. Lower if you have more than 256 characters of typeahead.
You can clear the screen by sending several formfeed characters. Additionally, some operating systems (like NetBSD) support a feature called ``whiteouts''.
Flip it over, put on your reading glasses.
By asking the user.
Only by force. Example code for Unix:
memmove(getppid() + getenv(NULL), getpid() + getenv(NULL), sizeof(environ);
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.
There are two good ways:
mmap() only 1k at a time, then, when you've read the first kilobyte of your input, use
memmove(mmapped_addr, mmapped_addr + 1024, 1024);
to move in the next kilobyte of data.
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);
fopen and goto.
Ask the user to open a new shell. The best way to do this is
system("echo Please open a new shell now."); sprintf(cmdstring, "echo Enter the command '%s' in it.", cmd); system(cmdstring);
This will not work if you haven't declared cmdstring properly.
Read the C++ FAQ.
They're always zero.
The traditional solution, pioneered by Microsoft, is to sell enough copies of your proprietary, slow, and limited software that everyone else supports your formats.
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.
Code like this ought to work.
long int foo() { return 2L +3; /* returns both values */ }
Try the following:
eval(s);
Now all you need to do is write eval().
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 rev 7.0b (3/7/95) */ /* RCS log: #log% - can anyone tell me why this doesn't work? * - joe, 2/12/93 */ /* * Copyright 1995 Berserkley Software Systems && Analytic Overdrive */ /* Parts of this header, including in particular the second and * third clauses of the first sentance of the fourth comment, were * based on copyright agreements from other sources, including * Xerox corporation. */ /* * 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 /* * common (portable) structures and functions */ /* * machine specific data */ #include <machine/math.h> #endif /* _MATH_H // prevent multiple inclusion by using C++ comments*/ ----cut here----
(Morons.)
You can do things like this:
DO CALL FORTRAN; fortran(); __LINE__ BASIC; basic(); sub pascal; pascal(); (((((lisp))))) lithp(); [*] &perl_c; perl():
(You can't call Ada from C; it's unsafe.)
[*] C is pass by value, of course.
Nope. However, the psychic friends network may have a lead. And they're not just a psychic, they're also a friend.
C++ is a superset of something, we're not sure what. You can use a C++ compiler to compile C code, but the results may surprise you.
From ftp://ftp.microsoft.com/ . Some of the code may look copyrighted; don't worry! The small companies that wrote it in the first place are not available for comment.
Next week. You missed the deadline. Tough, sucker.
We believe it has something to do with captivity; C comments in the wild mate and nest normally. The San Diego Zoo believes it has managed to convince some C comments to nest, but it's hard to tell how much of that is really in the preprocessor, and how much of it is just bovine fecal matter.
chr$(foo); You would have known this if you had an integer basic in ROM.
With linked lists of bitfields. You may also wish to simply use a large set of constants and some clever use of the switch statement, i.e.:
enum { zero, one, two, three };
int bitwise_or(int n, int m) { switch (n) { case three: return three; break; case two: switch (m) { case one: case three: return three; break; default: return two; break; } break; case one: switch (m) { case two: case three: return three; break; default: return one; break; } break; default: case zero: switch (m) { case one: return one; break; case two: return two; break; case three: return three; break; case zero: default: return zero; break; } break; } }
Obviously, you'll need to increase this slightly to deal with more than two bits. This is much more readable than the alleged ``C'' solution:
int bitwise_or(int n,int m){return n|m;}
Note how the lack of whitespace around operators obscures the functionality of the code. A clear argument for explicit statement of program logic over arcane operators, if I ever saw one.
The enum at the top isn't declared ``const int'', because the resulting ``const poisoning'' would require casts during all of the switch statements.
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.
Remove the comments; the no-op instructions generated by comments can slow your code down signifigantly. Similarly, shorten variable names. Most compilers, to implement pass by value, actually pass the names of variables in the stack; shorter variable names will reduce stack usage, and consequently execution time. If your compiler has good loop optimization, replace
foo();
with
do { foo(); } while (1 != 1);
which will likely receive more optimization.
Yes. About 10 ms per call. Only on machines which feature preincrement addressing.
You probably declared main as ``void main(void)''. It's also possible that the first statement in main is abort(); - by the as if rule, the compiler can abort at any time before then, too. Some compilers have bugs, and will produce buggy code for any module which includes the letters ``a'', ``b'', ``o'', ``r'', and ``t'' in that order before the first function declaration.
C programs are very territorial, and divide their code into segments. Violating these segments can trigger riots; similarly, pointers and integral constants are at the front of the bus, wheras arrays, strings, and other second-class data types are required to be at the rear of the bus. When they start forgetting their places, you can get a bus error. This is what the whole ``integral'' type thing is about - integrated bussing.
Your vendor's library is buggy; complain loudly. Don't send them any example code; they just ask for that so they can steal your trade secrets.
Yes. Unfortunately, it's probably broken. It's hard to tell.
You can't; YACC is written in C.
Ask any first year CS student. You may also wish to use your C compiler.
Just try comparing pointers near the original pointers.
That's a hard question. I'd suggest using an encyclopedia, or possibly a dictionary - look up ``yes''.
Like the first word of ``char *''. The accent is generally on the first syllable.
*sigh* I knew someone would ask that. (Editorial note: I recieved several corrections to minor factual errors when I first posted this.)
If you actually want to know something about C, get a good book (K&R is reccommended), and check out the real FAQ, which is posted monthly in comp.lang.c, and available by anonymous ftp from rtfm.mit.edu.
I have a small web page of C stuff:
http://www.solon.com/~seebs/c
and there is an excellent site at Lysator:
http://www.lysator.liu.se/c
For extra credit, see if you can figure out what all of the examples really do; most of them will compile, and all of them can be gotten to compile with sufficient #defines. (I think.)
The original comp.lang.c FAQ is maintained by Steve Summit, and many of the questions were stolen from it. Some of the idiotic misconceptions here are original, but many are from other sources. People have really said or advocated several of these; think about it. The Zork series may well be trademarked, but it was certainly an excellent game. Some of the mistakes may look similar to things warned against in C Traps and Pitfalls. And, of course, if Dennis Ritchie hadn't written C, these jokes would be much harder to understand.
Several people have contributed answers or questions, but I have lost the names in the mists of time.