As well, you may also want to take a look at our other Other FAQs, the Comeau C++ and C FAQ and the Comeau Templates FAQ.
Here's the current topics:
Note that we've broken our list down into categories, consider getting one or two from each category. Some you should get as references, others you should get to read from cover to cover.
Note that often there is a problem between technical accuracy and readability. You may have a very readable book that's telling you wrong things, or avoiding fundamentals or insights, but that's won't get you anywhere to be reading the wrong things albeit easily. The converse is a very accurate book that is not as easy to read. There is a price to pay either way, but generally you're better off with the technically correct text. We believe this is so for the short and long term. And in general, please make an effort to avoid product oriented books, or books with titles that just make things sound like everything will just be so great.
Categorically, we have not been satisfied with online tutorials (this does not mean that there are no good ones, just that we have not seen it yet). If you know of one that's excellent, don't hesitate to email us about it.
| news:alt.comp.lang.learn.c-c++ |
http://www.comeaucomputing.com/learn/faq |
| news:comp.lang.c news:comp.std.c |
http://c-faq.com |
| news:comp.lang.c++ news:comp.lang.c++.moderated |
http://www.parashift.com/c++-faq-lite/ Welcome to comp.lang.c++ http://www.slack.net/~shiva/welcome.txt |
| news:comp.std.c++ | http://www.jamesd.demon.co.uk/csc/faq.html |
| The Comeau C++ and C FAQ | http://www.comeaucomputing.com/techtalk |
| This document (The Comeau C++ TEMPLATES FAQ) | http://www.comeaucomputing.com/techtalk/templates |
| The Comeau C99 FAQ | http://www.comeaucomputing.com/techtalk/c99 |
In general, if you need a FAQ, check out http://www.faqs.org
The latest revision of Standard C, so-called C99, is also available electronically too from ANSI. ANSI C89 or ISO C90 is still currently available but only in paper form. For instance, Global Engineering Documents was carrying C89 (X3.159). Once at that link, click US, enter "x3.159" in the document number (NOT the document title) search box, and that'll get you the latest info from Global on this paper document (last we checked it was US$148).
struct xyz { int a; int b; int c[99]; };
// DI allow for that members can be named in initializer lists
// Note that member c is "zero'd" since it is not uttered in the init list
struct xyz AnXyz = { .b = 99, .a = -99 };
struct xyz AnXyz2 = { .b = 99 };
// DI's ok for array objects too
struct xyz AnXyz3 = { .c[2] = 44 };
int array[99] = { [33] = 33, [66] = 66 };
struct xyz AnXyz3b[] = { [5].c[2] = 44 };
struct abc { int d; struct xyz xyzmem; };
// DIs ok for subobject too
struct abc AnAbc = { .d = 11, .xyzmem.b = 33 };
// "weird" stuff too: take last DI, but eval all
// Look: member b done twice, last one "wins"
struct abc AnAbc2 = { .d = 11, .d = 22 };
int foo() { /* Computing Something... */ return 0; }
void bar()
{
// Function necessary because foo() is not constant
struct abc AnAbc3 = { foo(), .d = 22 };
}
int main()
{
// unions ok too
union U { int intmem; float floatmem; };
union U u = { .floatmem = 99.99 };
union U u2 = { .intmem = AnXyz2.b + 99 };
return 0;
}
// Compound literals avoid needing to create "funny named" object that
// might otherwise serve no other purpose but to be pointed to, etc.
// Some argue they are similar in nature to C++ construct calls.
//
// Compound literals are composed with a cast-like-kinda construct
// with a brace'd initializer to create unnamed array's.
int foo() { return 99; }
struct xyz { int i; int j; };
void bar(struct xyz dummy_arg) { }
void baz(struct xyz* dummy_arg) { }
// Initializers for the literals are required to be constant if in file scope
// Unnamed array is static if in file scope
int *p = (int []){ 1, 2 }; // p points to unnamed array of int[2]
int main()
{
// non-constant initializers ok in enclosing block
// unnamed array is auto here
// foo() only done once
int *p2 = (int []){ 1, foo() }; // ok
(int []){ 1, 2 } = 99; // Error
*(int []){ 1, 2 } = 99; // Ok, but yuck
// Note the literal need not always just be an array
p = &(int){ 1 }; // ok, but be careful
// const compound literals need not be distinct
const int *cix = (const int []){ 1, 2 };
const int *ciy = (const int []){ 1, 2 }; // Same literal?
// String literals do not have const in C. This alternative
// might help in some cases (perhaps wrapped in a macro??):
const char *ccp = (const char []){ "Comeau C/C++" };
// Pass a compound literal to a function
bar((struct xyz){ 123, 456 });
// Combo'd with DI's from above:
bar((struct xyz){ .i = 123, .j = 456 });
// Pass addr of literals:
baz(&(struct xyz){ 456, 789 });
}
#include <stdio.h>
#include <stdlib.h>
void funcWithVLA(int n)
{
// Note that during the lifetime of a vla, its size does not change
int vla[n];
// sizeof eval'd at run-time not compile-time
printf("%d\n", sizeof(vla)); // sizeof(int) * n
}
// Use * only in prototype, not def
// * indicates unspecified dimension
void funcTakingVLA(int size, int a[*]);
int Global = 99; // boo hiss
int GlobalVLA[Global]; // Error: VLA can't be extern
// extern's need constant for dimension
int main()
{
int n = 99;
int m = 999;
extern int externVla[n]; // Error: VLA still can't be extern
static int staticVla[n]; // Error: VLA can't be static either
static int (*p)[n]; // ok: p has block scope and is *ptr* to a VLA
int unknownSize[*]; // Error: VLA with unspecified bounds
// only allowed in function prototype scope
struct blah {
int vlamember[n]; // Error: struct members can't be VLAs
};
// Eval n at runtime, therefore autoVLA is a VLA
int autoVLA[n]; // ok
int twoD[n][m]; // ok: 2d array, and so on
int randVla[rand()]; // :) size expression not constant, watch out for 0
n = -99;
int negVla[n]; // Error: size shall evaluate > 0
// This will normally be a runtime thing, not compile time
// n eval'd here, not when VlaTD used
typedef int VlaTD[n]; // ok: has block scope
VlaTD someid; // ok
funcWithVLA(n);
funcTakingVLA(n, autoVLA);
// Remember, const is readonly in C, not as constant'y as in C++
const int dimension = 99;
int StillAVLA[dimension]; // Therefore, this is a VLA
// VLA in for loop just fine:
for(int VLAInForLoop[dimension], i = 0; i < dimension; i++) {
// ...
// code apparently using VLAInForLoop
// ...
}
}
void funcTakingVLA(int size, int a[size])
{
}
#include <stdlib.h>
struct flex {
int mem; // Flex array must have a named member
int arrayWoBoundsSpecified[]; // Flex member must be last member
};
struct NotAflex {
int a[]; // Error: Flex member must be last member
// Therefore incomplete type should be complete
int mem;
};
int main()
{
// "as if" len = offsetof(struct flex, arrayWoBoundsSpecified)
size_t len = sizeof(struct flex);
// Flexible array members might be useful for reading record
// from a comm line, or getting variable length information.
//
// The struct object "containing" with the flex array cannot be
// longer than actual underlying object being accessed.
//
// These examples use malloc(). It shouldn't have to
// be limited to just that, but will be where it will be
// used most
//
// (Do examples with DIs and CLs??)
struct flex *p = malloc(len + 100);
// This tends to product a dynamic type.
// That is it is now "as if":
// struct {
// int mem;
// // Assuming sizeof(int) is 2, then 100 / sizeof(int) is 50
// int arrayWoBoundsSpecified[50];
// };
p->arrayWoBoundsSpecified[49]; // ok
struct flex *p2 = malloc(len + 80);
// This is now "as if":
// struct {
// int mem;
// // Assuming sizeof(int) is 2, then 80 / sizeof(int) is 40
// int arrayWoBoundsSpecified[40];
// };
p2->arrayWoBoundsSpecified[39]; // ok
struct flex *p3 = malloc(len + 3);
// This is now "as if":
// struct {
// int mem;
// // Assuming sizeof(int) is 2, then 3 / sizeof(int) is 1
// int arrayWoBoundsSpecified[1];
// };
p3->arrayWoBoundsSpecified[0]; // ok
struct flex *p4 = malloc(len + 1);
// This is now "as if":
// struct {
// int mem;
// // Assuming sizeof(int) is 2, then 1 / sizeof(int) is 0
// // The bounds therefore becomes 1
// int arrayWoBoundsSpecified[1];
// };
// Even though the bounds became 1, these are undefined
p4->arrayWoBoundsSpecified[0]; // undefined behavior
int *pi = &p4->arrayWoBoundsSpecified[1]; // undefined behavior
struct flex *p5 = malloc(sizeof *p5 + X * sizeof(int)));
// The previous examples used "nonsense constants" such as
// 100, 80, etc for the sizes, so p5 is an example with
// a more realistic form that the malloc would look like.
//
// So, sizeof *p5, will give you the sizeof what p5 points to,
// which is a struct flex, and then since arrayWoBoundsSpecified
// is type int, we need X times the sizeof that, to get us a int[X].
//
// Obviously you'll need to declare and provide/compute a value
// for X.
}
#include <stdio.h>
int main()
{
// _Bool can hold 0 or 1
// _Bool is an unsigned integer type
_Bool b = 1;
struct xyz {
_Bool mem : 1; // _Bool bitfields allowed
};
printf("%d\n", b); // 1
b = 0;
printf("%d\n", b); // 0
_Bool *pb = &b;
// If the expression evaluates to 0, then it converts to _Bool as 0, else 1
b = pb;
printf("%d\n", b); // 1
b = -1;
printf("%d\n", b); // 1
b = (pb == 0);
printf("%d\n", b); // 0
return 0;
}
// #define's bool, true, false, __bool_true_false_are_defined macros
// as _Bool, 1, 0, and 1 respectively
#include <stdbool.h>
void foo()
{
int this = 99;
int that = -99;
bool b;
if (this || that)
b = true;
else
b = false;
}
void foo(int array[static 99]);(Better example needed.)
#include <stdio.h>
int main()
{
printf("%s\n", __func__); // output "main"
return 0;
}
Because __func__ was uttered, then main is written by the compiler "as if":
int main()
{
// This line implicitly added by the compiler:
static const char __func__[] = "main";
printf("%d\n", __func__);
}
// SomeFile.c
static int internalId = 99;
// inline is a hint, not a requirement to honor.
// An external definition has not been provided for foo
// Other translation unit's don't find this definition
inline void foo()
{
// External linkage inline function can't ref a modifiable static
static int modifiable = 99; // Error
// External linkage inline function can't reference internal linkage id's
int i = internalId; // Error
}
extern inline void foo(); // ok, now an external definition provided
static inline int bar() { return 99; } // ok
inline int baz() { return 99; } // ok
inline void NotDefined(); // Error: Needs to be defined in this translation unit
int main()
{
/* May or may not use inline definition */
foo();
int i = baz(); // if inline'd, then "as if": int i = 99;
}
#include <stdio.h>
// In C89/90, you need multiple macros with "funny" names to do this.
// Anyway, in this example, the arguments passed (those represented
// by the ...) replace the __VA_ARGS__ when the substitution occurs.
#define DoLogFile(...) fprintf(stderr, __VA_ARGS__)
// Variadic macros also help out if you want to effectively
// pass one argument that contains commas
#define MakeName(...) #__VA_ARGS__
// Of course, the macro can also take other args, so long as
// the ... is last
#define output(FILEptr, ...) fprintf(FILEptr, __VA_ARGS__)
// This is not right, since this is NOT a variadic macro
#define mac(arg) foo(arg, __VA_ARGS__)
int main()
{
int bound = 99;
int current_index = 88;
int linenumber = 77;
DoLogFile("Detected array out of bounds\n");
DoLogFile("Bound = %d, current index =%d\n", bound, current_index);
DoLogFile("Missing semicolon on line %d\n", linenumber);
output(stderr, "Detected array out of bounds\n");
char *p;
p = MakeName(Mary);
p = MakeName(Doe, John);
p = MakeName(Martin Luther King, Jr.);
// Combo two variadic macros
DoLogFile("MakeName=%s\n", MakeName(This is a test, yes it is));
}
// _Complex and _Imaginary are not required in freestanding implementations
int main()
{
_Complex double cd = -99.99; // imaginary part is zero
// either order ok
double _Complex cda[] = {
cd, -cd, cd, 1.23 * __I__
};
double d = cda[1]; // imaginary part tossed
_Imaginary double id = 99.99 * __I__;
double x = id; // _Imaginary -> real --> 0
}
A new header is also available that brings in various macros:
#include <complex.h>
void foo()
{
double complex c = 1 + 2.3 * I; // 1.0+2.3i
}
Various routines are also declared in <complex.h> including:
#include <stdio.h>
int main()
{
for (register int i = 0; i < 99; i++)
printf("%d\n", i);
i = 0; // Error: i no longer in scope
}
int main()
{
// This is a test
return 0;
}
Note also that // is in addition to, not instead of /* */ comments, so both can be used:
/*
* This is old style comments
* Might explain an algorithm here
*/
void foo()
{
bar(); // Non-obvious remark here perhaps
}
Nesting the two different styles of comments is generally ok:
// This has new // C++ style comment // This has an /* old style comment */ in it /* This has a // C++ style comment */since the contents of the comment don't confuse either comment. As usual, this is no good though:
/* An old style comment containing an /* old style comment */ */Take note also that the end of line in the new comments must account for line splicing:
// This is a comment \ and this is part of the same comment as one "long line"!This means that you should not convert code like this:
#define macro(arg1, arg2) \
SomeFunction(arg1, /* Some remark */ \
arg2 /* Some other remark */ \
)
into this:
#define macro(arg1, arg2) \
SomeFunction(arg1, // Some remark \
arg2 // Some other remark \
)
because the 4 physical lines then become one longer logical line, as if:
#define macro(arg1, arg2) SomeFunction(arg1, // Some remark arg2 // Some other remark )and hence then a post-preprocessor stage of compilation only sees this:
#define macro(arg1, arg2) SomeFunction(arg1,
_Pragma(L"Some literal with \" and \\")In processing, the beginning and ending double quote is removed, as is the backslash in a backslashed double quote or backslash, as is a literal prefix of L. In other words, the above becomes:
#pragma Some literal with " and \Since the intent is to deal with macro replacement, the above equivalence is desirable because of something such as:
// Notice the stringizing operator upon arg #define PragmaFE(arg) _Pragma(#arg) #define PragmaPack(arg) PragmaFE(pack(arg))The win here is that this alternative form can help diminish the slew of #if defineds (and perhaps header files that might go along with them) that are often necessary to get some special implementation-defined things done with some code (remember, a normal pragma might apply to something inside a function too (and furthermore, can't be applied to say a function-like macro)). This means things can be arranged into a header file, and then just used:
#include "pragmastuff.h"
CallingConvention(Pascal)
void foo() { }