====== C Tips ==
This is about ISO C and its standard library. POSIX/Linux enhancements and features are described in [[:becki:my:linux:linux programming]]. How to build applications is described in [[build tools]].
===== CLI args and main() ==
int main(int argc, char **argv){
char * progName= argv[0]; // Filename of programm itself
if (argc >= 2) char * firstArg= argv[1]; // First Argument
}
int main(void){}
// is also possible (Carm p.416)
// don't omit void! (Carm p.278)
===== C Program Structure ==
{{page>becki/my/linux/design_blog/2017-01-20_c_program_structure&noheader}}
===== Position of Pointer Sign ======
Some investigations:
int main(int argc, char* argv[]) // Stroustrup p.126
int main(int argc, char* argv[]) // Josuttis p.21
int main(int argc, char* argv[], char *env[]) // (!) Breymann p.216
int main(int argc, char *argv[]) // glibc reference
int main(int argc, char *argv[]) // Kernighan / Ritchie
int main(int argc, char *argv[]) // Harbison / Steele
int main(int argc, char **argv) // gtk reference
int main(int argc, char **argv) // qt reference
int main(int argc, char **argv) // fluxbox source
-> I use
char *cp
because
- it seems to be more common
- declarations like "int a, *ap;" are possible
===== Loops ==
==== Loops and break ==
int i= 0;
while (i
is the same as:
int i;
for (i=0; i
==== While and For ==
for (expr1; expr2; expr3)
statement
is the same as((The C programming language p.59)):
expr1;
while (expr2) {
statement
expr3 //expr3 comes after statement
}
===== Standard In- and Output ==
==== stdin ==
/* Read a character from stdin: */
int i= getchar();
/* Read stdin line by line into the array lin: */
char lin[MAX_LINE_LEN];
while (fgets(lin, MAX_LINE_LEN, stdin)) {/* do some thing */}
If input line lenght is unknown, use ''getline()'' instead of ''fgets()''!
(See ''freesigs/io_modbus'')
''scanf'' can also be used for reading from ''stdin''.
==== stdout, stderr ==
/* Write a character to stdout and stderr: */
int i= 'c';
putchar(i);
putc(i, stderr):
/* Write a line to stdout and stderr: */
printf("%s=%u\n", key, value); // writing to stdout (buffered)
fprintf(stderr, "%s=%u\n", key, value); // writing to stderr (unbuffered)
Writing to ''stderr'' is unbuffered, writing to ''stdout'' is buffered ((CARM p.351))
⇒ Always use ''stderr'' for debugging messages ((RRUSP p.68))
===== Constants ======
==== const =====
const int ic = 6;
/* int const ic = 6; Seems to be the same (gcc 3.4.6 / 2007-10-25) */
ic = 7; //invalid
ic++; //invalid
see CaRM p.81
==== const and pointer =====
const int * pointer2const; // pointer to constant data
int * const constPointer; // constant pointer (points always 2 the same place)
const int * const constPointer2const; // constant pointer to constant data
see CaRM p.81 and source code of CVS
==== const and array of pointers ==
Rule: An array type is always automatically converted to a constant pointer to the first element
int a, b;
const int * const api[] = {&a, &b};
const int * const * const api = {&a, &b};
*(api[0]) = 9; // forbidden by FIRST const in array definition
api[0][0] = 9; // forbidden by FIRST const in array definition
api[0] = &b; // forbidden by SECOND const in array definition
Tested with gcc 3.3.4
==== const and (array of) function pointers ==
int if1(void) {return 1;}
int if2(void) {return 2;}
void pointer2FunctionTest(void) {
int (* fp1)(void) = if1; // fp1,fp2: pointer to function returning
int (* const fp2)(void) = if2; // int and empty parameter list
fp1 = if2; // valid
fp2 = if1; // invalid: ok
}
void arrayOfPointers2FunctionsTest(void) {
int (* fa[])(void) = {if1, if2};
int (* const cfa[])(void) = {if1, if2};
fa[0] = if2; // valid, but intended?
cfa[0] = if2; // invalid because of const: ok
}
Note the position of the const variable, this is the only position of const that
makes sense (Tested with gcc 3.3.4 and CadulCompiler for Rmos)
==== const in function parameters ==
void fkt(const int a, const int *bp, int * const cp) {
a++; // invalid!
bp++; // valid
(*bp)++; // invalid!
cp++; // invalid!
(*cp)++; // valid
}
pointer to constant data (bp) is imho the only useful & reasonable use
==== function returning const ==
int if1(void) {return 1;}
const int cif1(void) {return 1;}
void functionReturningConstTest(void) {
int i; const int ci;
i = cif1(); i = if1(); // both valid
ci = cif1(); ci = if1(); // both INVALID!
i = (cif1())++; i = (if1())++; // both INVALID!
i = ++(cif1()); i = ++(if1()); // both INVALID!
}
-> function returning const is imho useless
==== function returning const pointer ==
int * ipf(void) {return 0;}
const int * cipf(void) {return 0;} // funct. returning pointer 2 constat data
void functionReturningConstPointerTest(void) {
int *ip; const int *cip;
ip= ipf(); // ok
ip= cipf(); // generates warning (gcc): imho better would be an error!
cip= ipf(); // ok
cip= cipf(); // ok
}
==== Definition of constant Strings ==
=== Getting started ==
[static] const char mystring[]= "String" // right, needs 6 Bytes
[static] const char *mystring= "String" // false, needs 6 Bytes + Pointer
* ''static'' to limit the scope for global strings. Not necessary inside a code block.
* see also [[http://www.dclc-faq.de/kap2.htm|de.comp.lang.c FAQ]] -> Frage 2.2 / K&R p.101 / Carm p.124
* //Writable// strings must be declared as array (eg ''char a[]= "aff";'') not as pointer. See Carm p 32
=== Detailed Description ==
/** Array of constant data.
Is automatically converted to a CONSTANT of type "pointer to const char"
(the type of the array-elements) wich contains the address of the first
element. See CARM p 95. Best way to initalize strings.
*/
const char a[]= "Alma";
/** Constant pointer to constant data, but not a CONSTANT (like a above)
Intitalizing a string like this is bad, see above
*/
const char * const b= "Berta";
/** Same type as b, but ok for a re-use of a e.g. as function argument. */
const char * const c= a;
/** Array of constant pointers (second const) to constant data (first const)
1st const necessary because of a */
const char * const apc[] = {
a, "Willi", /* perfectly legal */
/* b, c // illegal, because extern or static variables can only be
// initialized with CONSTANTS not constant variables
// see [[Initialisation of variables]] */
};
/** Constant Pointer (3rd const) to constant pointer (second const)
to constant data (first const) */
const char * const * const ppc= apc;
int main(void) {
/* a = 0; //err: Every array is conv. to const ptr to 1st element */
/* b[0] ='A'; //err: a[] is declared as const */
/* apc[0] = 0; //err: because of 2nd const in apc definition */
/* apc[0][0]='d'; //err: because of 1st const in apc definition */
/* ppc = 0; //err: because of 3rd const in ppc definition */
/* ppc[0] = 0; //err: because of 2nd const in ppc definition */
/* ppc[0][0]='d'; //err: because of 1st const in ppc definition */
return 0;
}
==== sizeof ==
//Feld von Zeigern auf Funktionen:
static const unsigned char (*setS5Bit[])(unsigned char zielNr, unsigned char bit)={
NULL,//Reserviert, wenn Eingang nicht aktiv
konvKom0SetS5Bit,
konvKom1SetS5Bit,
extStmSetS5Bit,
extBtmSetS5Bit,
extGeraetSetS5Bit
};
#define GETS5BITADR_FKTANZ (sizeof (setS5Bit) / sizeof (setS5Bit[0]))
Bestimmung der Größe des obigen Arrays:
Einsicht in die vom Preprocessor erzeuge Zwischendatei peripher.i (mit der Compileroption -VCPP zeigte, daß GETS5BITADR_FKTANZ wirklich nur textuell durch die sizeof- Klammerausdrücke ersetzt wird, und keine Berechnung erfolgt.
Einsicht in das generierte Assemblerfile peripher.asm ergab, daß die sizeof-Operatoren zur Compilierungszeit und nicht zur Laufzeit ausgeführt werden.
-> Keine Verschwendung von Laufzeit.
===== Initialisation of Variables ==
/* Extern & static variables must be initialized with a constant expression:
See C&R 4.9 p.83
*/
int a; /* uninitialized extern or static variable defaults to 0 */
int b=1;
const int c=3;
//int m= b; /* error in c! (no error in c++) */
//int n= c; /* also error in c! (no error in c++) */
/* automatic variables need no constant expression: See C&R 4.9 p.83 */
int main() {
int u= b+c; /* valid shortcut for: int u; u=b+c; */
int v[]= {a,b}; /* valid in c with gcc & in c++ */
return 0;
}
Note: The initialisation of the (stack-)array v is valid with gcc, but issues a warning when gcc is called with the -pedantic switch.
==== Cadul Compiler Deficiency ==
int anInt;
struct Point {int x; int y;};
struct Point aPoint= {2,3};
int main(){
int o= anInt;
int p[]= {anInt,anInt};
struct Point q={3,4};
struct Point r[]={{3,4},{5,6}};
struct Point s=aPoint;
struct Point t[]={aPoint,aPoint}; /* error with Cadul! (no error with gcc) */
}
==== Transfer of Array Sizes ==
/* arraySource.c: */
int arr[]= {3, 2, 1};
const unsigned ARR_CNT= sizeof arr / sizeof arr[0];
/* arraySource.h: */
extern const unsigned ARR_CNT;
/* target.c: */
#include
#include
#include "arraySource.h"
int main(int argc, char **argv) {
int size= atoi(argv[1]);
static int staticCmdArr[size]; /* Always Error! */
int stackCmdArr[size]; /* works with gcc without -pedantic-error */
static int staticTransArr[ARR_CNT]; /* Always Error! */
int stackTransArr[ARR_CNT]; /* works with gcc without -pedantic-error */
return 0;
}
#Compiler Commands:
gcc -Wall -ansi -pedantic-error -c target.c && gcc -c arraySource.c && gcc target.o arraySource.o && a.out 7
gcc -Wall -c target.c && gcc -c arraySource.c && gcc target.o arraySource.o && a.out 7
FIXME No satisfying solution so far --- 2006-08-28 12:02
===== static ==
static int eumel= 0;
==== Outside of a fuction (global Variable) ==
To prevent linker problems when other object files use other global variables with the same name.
==== Inside a fuction ==
* The Variable is actually created in the data segment of the programm & not on the stack.
* The value of the variable remains from one call to the next call of the function
* :?: ''static'' should not be necessary for ''const'' variables in functions; the compiler is probably clever enough to put constant values to the proper places in memory.
===== How to select Integer Variable Types ==
- Always use ''int'' (also when int is way too big or the value will never be never negative, eg. counter variable in for loops), unless one or more of the following exceptions apply:
- Use ''unsigned int'' when [[http://www.dclc-faq.de/kap10.htm|only positive values are allowed]]. This saves you from the overhead of testing for negative values in function arguments and returned values from functions.
- Use ''unsigned'' types when bit operations are performed (unsigned types with proper size recommended)
- Use another, smaller type when space is relevant (eg in ''struct'' definitions or large arrays)
- Use a bigger type when the space in ''int'' is not sufficient
===== Private Members in structs ==
Any pointer type may be an incomplete type. This can be used to get private members in an object:
==== Library Code ==
/* file: point-private.h */
struct point {
int x;
int y;
};
/* file: point.c */
#include
#include "point-private.h"
struct point * point_new(int x, int y) {
struct point *p= malloc(sizeof(struct point));
p->x= x;
p->y= y;
return p;
}
int point_get_x(struct point *this) {
return this->x;
}
/* file: point.h */
struct point * point_new(int x, int y);
int point_get_x(struct point *this);
==== Client Code ==
#include
#include "point.h"
int main(void) {
struct point *p = point_new(7,4);
printf("x=%d\n", point_get_x(p));
//printf("x=%d\n", p->x); // Error: incomplete type
return 0;
}
===== Unsorted Tips ==
* Use ''stdint.h''. It offers exact length types; smallest types of at least given length and most efficient types
* Use ''limits.h'' to get the ranges of integer types ((CARM p.112))
* [[http://library.gnome.org/devel/glib/stable/|Glib]] is to C what the STL is for C++ or the Platform API for Java. IBM has an intro: [[http://www.ibm.com/developerworks/linux/library/l-glib.html|The wonders of GLib]] (currently broken --- 2010-10-20)
* Buffer for strings: Define a constant for the maximal stringlen eg: ''#define MAXFOOLEN 80'' and reserve memory with one byte more for the 0-terminator: ''char sbf[MAXFOOLEN+1];''
* :?: Test: Include header files which are necessary for the interface in ''foo.h''. Include header files necessary only for the implementation in the ''foo.c''. The dependencies for the makefile is the sum of both.
* Passing 0-termintad arrays saves from defining and additionally passing the array size. This is useful for arrays of any type, not just char[].
* Design constructors to expect only absolutely essential information. Move optional parameters to other setup functions for the class.
===== 2do / Pending ==
* enum usage with typedef: RRPUP p. 228
* Add object oriented coding; Class templates and howto
* [[http://www.elektroniknet.de/home/embeddedsystems/fachwissen/uebersicht/software/entwicklungssoftware/unit-tests-mit-open-source-werkzeugen/|Unit-Tests mit Open-Source-Werkzeugen]]