cpp-cheat/c.c
2015-05-19 09:26:58 +02:00

9960 lines
285 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
ANSI C cheat.
Small comments on comparing ANSI C with extensions are acceptable.
This cheatsheet is being split up into smaller parts to c/
*/
#define UNDEFINED_BEHAVIOUR
/*
# include
Look in standard dirs directly:
#include <file.h>
Looks in current dir first:
#include "file.h"
*/
#include <assert.h>
#include <ctype.h> /* isspace, isdigit, ispunct, tolower, toupper */
#include <errno.h>
#include <fenv.h>
#include <float.h>
#include <inttypes.h> /* PRIxPTR */
#include <limits.h> /* *_MAX, *_MIN for integer types */
#include <locale.h>
#include <setjmp.h> /* setjmp, longjmp */
#include <stdarg.h> /* ..., va_list, va_start, va_arg, va_end */
#include <stddef.h> /* offsetof, type_t */
#include <stdlib.h> /* malloc, EXIT_SUCCESS, EXIT_FAILURE: */
#include <stdio.h> /* printf, puts */
#include <string.h> /* sprintf, strlen, strcpy, memset, memcmp */
#include <math.h>
#include <time.h> /* time() */
#if __STDC_VERSION__ >= 199901L
/* Not yet implemented in GCC 4.8. */
/*#include <thread.h>*/
#if __STDC_VERSION__ >= 201112L
#include <stdnoreturn.h>
#endif
#endif
/*
One way to define constant is with preprocessor directives.
However using a const may be a better idea because:
- constants have scope
- produce meaningful error messages
*/
#define PI 3.14
/*
Example where this would cause problems:
int PI = 3.14;
`PI` expands to `3.14`
Compiler reads:
int 3.14 = 3.14;
but it will be hard to figure error message.
Compare this with the very simple message generated if PI were a constant
*/
/* Use parenthesis or order of operation might destroy you: */
#define PI_PLUS_ONE (3.14 + 1)
/* common recipe to control compilation: */
#define DEBUG
#ifdef DEBUG
int debugVar;
#endif
/* # # line */
/* From now on, counts from given line to report errors: */
/* # line 1 */
/* # global scope */
/* This is a global variable: can be accessed and modified everywhere */
int global = 1;
/* OK! */
int global2 = 1+1;
int ret1() {
int i;
/* before main! */
return 1;
}
/* ERROR: only var declarations with const initialization allowed */
/* Non-const. */
/*int global2 = global+1;*/
/* Funcion call. */
/*puts("asdf");*/
/*int global3 = ret1();*/
/* Branching statement. */
/*if(1){}*/
/* ERROR */
/* Cannot create scopes here like that */
/* They'd be useless anyways. */
/*{}*/
int same_name_as_variable() { return 0; }
/* Typecast */
typedef struct void_ptr_cb_payload { int i; } void_ptr_cb_payload;
int void_ptr_cb(int i, void* payload) {
void_ptr_cb_payload* pay = payload;
return i + pay->i;
}
typedef struct void_ptr_cb_payload2 { int i; int j; } void_ptr_cb_payload2;
int void_ptr_cb2(int i, void* payload) {
void_ptr_cb_payload2* pay = payload;
return i + pay->i + pay->j;
}
int void_ptr_caller(int i, int (*cb)(int i, void* payload), void* payload) {
return i + cb(2, payload);
}
/* Pointer array */
int* get_arr(int i) {
/*int is[] = {i};*/
/*return is;*/
/* WARN */
/* return adress of local var */
/* data is destroyed on return! */
int* ip = (int*) malloc(sizeof(int) * 1);
return ip;
}
/* cheatsheet on pointers and arrays */
void print_array(int **mat, int m, int n) {
int i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("%d ", mat[i][j]);
}
printf("\n");
}
}
int goto_func(int i) {
/*goto goto_func_after;*/
in_func_label:
return 1;
}
int setjmp_func(int jmp, jmp_buf env_buf) {
if (jmp)
longjmp(env_buf, 1);
else
return 1;
}
/* Functions */
/*
Declaration vs definition
*/
void decl_def();
void decl_def();
void decl_def() {}
/* ERROR redefine */
/*void decl_def() {}*/
void decl_def_no_arg_name(int i, float f, char d) {}
/* ERROR */
/*void def_no_argname(int){}*/
int factorial2funcs1(int);
int factorial2funcs0(int n){
if (n != 1) {
return n*factorial2funcs1(n - 1);
}
return 1;
}
int factorial2funcs1(int n){
if (n != 1) {
return n*factorial2funcs0(n - 1);
}
return 1;
}
#if __STDC_VERSION__ <= 199901L
default_return_type() {
return 1;
}
#endif
int proto_empty_definition() {
return 1;
}
/* Two decls on the same line, with same return type: */
int decl_1(), decl_2();
int decl_1(){ return 1; }
int decl_2(){ return 2; }
/* ERROR cannot define on same line */
/*int decl_3(){return 3;}, decl_4(){return 4;};*/
/* Can declare a function that returns int and a int var with the same `int`. */
/* Very confusing! */
int decl_and_initialize_func(), decl_and_initialize;
int decl_and_initialize_func(){ return 0; }
int k_and_r(a, p)
int a;
char *p;
{
return 0;
}
/*
# [*]
The "[*]" declaration syntax is possible to avoid naming parameters.
*/
void vla_arg(size_t, int vla[*]);
void vla_arg(size_t size, int vla[size]) {}
void vla_arg_k_and_r(size, vla)
/*int vla[size];*/ /* ERROR: must come after. */
size_t size;
int vla[size];
{}
/*
# overload
There is no function overloading in C to avoid name mangling:
C ABI simplicity is one of it's greatest strengths:
http://stackoverflow.com/questions/8773992/c11-type-generic-expressions-why-not-just-add-function-overloading
C11 introduces generics, which allow for a similar, albeit more limited effect.
*/
void overload(int n) {}
/* ERRORS: */
/*void overload(float n) {}*/
/*void overload(int n, int o) {}*/
int * int_ptr_func_int_ptr(int *ip) {
(*ip)++;
return ip;
}
int int_func_int(int i) {
return i;
}
void func_int(int i) {}
void func_float(float f) {}
void func_double(double d) {}
void func_string_abc(char s[]) { assert(strcmp(s, "abc") == 0); }
void func_string_const_abc(char const s[]) { assert(strcmp(s, "abc") == 0); }
void func_string_modify(char s[]) { s[0] = '0'; }
void func_array(int a[]){
assert(a[0] == 1);
}
void func_array_modify(int a[]) {
a[0] = -1;
}
struct struct_func_struct {
int i;
int j;
};
struct struct_func_struct struct_func() {
return (struct struct_func_struct){ 0, 1 };
}
struct func_struct { int i; };
void func_struct_1(struct func_struct s) {
assert(s.i == 1);
}
void func_int_ptr (int *i) {}
void func_int_arr (int i[]) {}
void with_static_var(int *i_out, int *si_out) {
int i = 0;
/* static initialization is evaluated only once */
/* the first time this function is called */
static int si = 0;
i++;
si++;
*i_out = i;
*si_out = si;
}
int add_int(int n, int m) {
return n+m;
}
int sub_int(int n, int m) {
return n-m;
}
int int_int_int_func(int m, int n) {
return m + n;
}
int int_func_func_int_int(int (*function_ptr)(int, int), int m, int n) {
return (*function_ptr)(m, n);
}
/*
function struct args
how to deal with passing structs to/from functions
*/
struct FuncReturn { int i; };
struct FuncReturn structReturn(struct FuncReturn sIn) {
struct FuncReturn s_out;
s_out.i = sIn.i + 1;
return s_out;
}
/*
# variadic functions
These are functions with a variable number or arguments, just like `printf`.
# va_start
va_start(varname, last_argname)
Initialize va_list variable varname. Indicates that varargs come after numargs.
# Get number of variadic arguments
TODO I think it is impossible except from another argument.
`printf` just deduces that form the format string, and reads the stack away.
*/
int variadic_add(int numargs, ...) {
va_list args;
va_start(args, numargs);
int sum = 0;
for(int i = 0 ; i < numargs; i++) {
int arg = va_arg(args, int);
sum += arg;
}
/* You MUST do this. TODO ehy? */
va_end(args);
return sum;
}
/*
This function illustrates how to va args from one function to another.
# vprintf
This is the raison d'etre for the `vprintf` family, which takes a va_list argument.
*/
int sprintf_wrapper(char *s, const char *fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf(s, fmt, args);
va_end(args);
return ret;
}
/* # return const from func */
const int const_int_func() {
return 0;
}
const int* const_int_ptr_func_int_ptr(int *ip) {
(*ip)++;
return ip;
}
const struct struct_func_struct const_struct_func() {
return (struct struct_func_struct){ 0, 1 };
}
#if __STDC_VERSION__ >= 199901L
void const_array_size_argument(int is[const]) {
is[0] = 1;
int j;
/* Compilation ERROR: assignment of read-only parameter is: */
/*is = &j;*/
}
#endif
/* restrict */
void restrict_double_add(int * restrict i, int * restrict j, int * restrict add) {
*i += *add;
*j += *add;
}
void double_add(int *i, int *j, int *add) {
*i += *add;
*j += *add;
}
/* It makes no sense to mark a single pointer as restricted. */
void restrict_double_add_one_restrict(int * restrict i, int *j, int *add) {
*i += *add;
*j += *add;
}
/*
This declaration is required!
- http://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99
- http://stackoverflow.com/questions/12747198/compiling-error-when-std-gnu99-and-inline-function-is-used
*/
int inline_func(int i);
inline int inline_func(int i) { return i + 1; }
#if __STDC_VERSION__ >= 199901L
int static_array_argument(int is[static 3]) {
return is[3];
}
#endif
/* _Noreturn */
_Noreturn void noreturn_func() { exit(0); }
noreturn void noreturn_func2() { exit(0); }
#ifdef PROFILE
const static int n_prof_runs = 100000000;
/* Only the loop. */
/* Discount this from every other profile run */
void loop_only_prof(int n) {
int i;
for(i=0; i<n; i++);
}
void while_only_prof(int n) {
int i = 0;
while(i < n)
++i;
}
void int_assign_prof(int n) {
int i,j;
for(i=0; i<n; i++)
j=1;
}
void do_nothing(){}
void func_all_prof(int n) {
int i;
for(i=0; i<n; i++)
do_nothing();
}
static inline void inline_do_nothing(){}
void inline_func_call_prof(int n) {
int i;
for(i=0; i<n; i++)
inline_do_nothing();
}
void int_sum_prof(int n) {
int i, j = 0;
for(i=0; i<n; i++)
j = j + 0;
}
void int_sub_prof(int n) {
int i, j = 0;
for(i=n; i>0; i--);
j = j - 0;
}
void int_mult_prof(int n) {
int i, j = 1;
for(i=0; i<n; i++)
j = j * 1;
}
void int_div_prof(int n) {
int i, j = 1;
for(i=0; i<n; i++)
j = j / 1;
}
void float_sum_prof(int n) {
float f;
int i;
for(i=0; i<n; i++)
f = f + 0.0;
}
void float_sub_prof(int n) {
float f;
int i;
for(i=0; i<n; i++)
f = f - 0.0;
}
void float_mult_prof(int n) {
int i;
float j;
for(i=0; i<n; i++)
j = j * 1.0;
}
void float_div_prof(int n) {
int i;
float j;
for(i=0; i<n; i++)
j = j / 1.0;
}
void putsProf(int n) {
int i;
for(i = 0; i < n; ++i)
puts("a");
}
void stack1b_prof(int n) {
int is[1];
int i;
for(i = 0; i < n; ++i) {
int is[1];
}
}
void stack1kb_prof(int n) {
int is[1];
int i;
for(i = 0; i < n; ++i) {
int is[0x800];
}
}
void stack1mb_prof(int n) {
int is[1];
int i;
for(i = 0; i < n; ++i) {
int is[0xF0000];
}
}
void heap1b_prof(int n) {
char* cp;
int i;
for(i = 0; i < n; ++i) {
cp = (char*) malloc(sizeof(char) * 1);
free(cp);
}
}
void heap1kb_prof(int n) {
char* cp;
int i;
for(i = 0; i < n; ++i) {
cp = (char*) malloc(sizeof(char) * 0x800);
free(cp);
}
}
void heap1mbProf(int n) {
char* cp;
int i;
for(i = 0; i < n; ++i) {
cp = (char*) malloc(sizeof(char) * 0xF0000);
free(cp);
}
}
#endif
/* # Algorithms */
/* Simple fun algorithms. */
/* Random. */
/* Returna a random float in a range. */
float rand_range(float a, float b) {
return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
/* a pow b naive. */
int pow2(int a, int b) {
int res = 1;
int i;
for(i=0; i<b; i++)
res *= a;
return res;
}
/* TODO does not work. */
float pow2f(float a, float b) {
float res = 1.f;
float i;
for(i = 0; i < b; i++)
res *= a;
return res;
}
/* File IO */
/*
Standard action to take in case of an IO error.
*/
void io_error(char *function, char *path){
fprintf(stderr, "eror: %s errno = %d, path = %s\n", function, errno, path);
exit(EXIT_FAILURE);
}
/*
Returns the size of the given open `FILE*`.
If an error occurs, returns `-1L`.
Does not work for pipes.
*/
long fget_file_size(FILE *fp) {
long oldpos;
long return_value;
oldpos = ftell(fp);
if (oldpos == -1L) {
return -1L;
}
if (fseek(fp, 0, SEEK_END) != 0) {
return -1L;
}
return_value = ftell(fp);
if (return_value == -1L) {
return -1L;
}
/* retore old position */
if (fseek(fp, oldpos , SEEK_SET) != 0) {
return -1L;
}
return return_value;
}
/*
Same as `file_size`, but takes the path instead of a `FILE*`.
*/
long file_size(char *path) {
FILE *fp;
long retur_value;
fp = fopen(path, "r");
if (fp == NULL) {
return -1L;
}
retur_value = fget_file_size(fp);
if (fclose(fp) == EOF) {
return -1L;
}
return retur_value;
}
/*
Read the entire file to a char[] dynamically allocated inside this function.
Returns a pointer to the start of that array.
In case of any error, returns NULL.
The entire file must fit into the memory avilable to the program.
*/
char *file_read(char *path) {
FILE *fp;
char *buffer;
long fsize;
fp = fopen (path , "rb");
if (fp==NULL) {
return NULL;
}
fsize = fget_file_size(fp);
if (fsize < 0){
fprintf(stderr, "could not determine lenght of:\n%s\n", path);
return NULL;
}
buffer = (char*)malloc(fsize);
if (buffer == NULL) {
return NULL;
}
if (fread (buffer, 1, fsize, fp) != fsize) {
return NULL;
}
if (fclose(fp) == EOF){
return NULL;
}
return buffer;
}
/*
Write null terminated string to file
Returns `-1` on failulre, 1 on success.
*/
int file_write(char *path, char *write_string) {
long len;
char *buffer;
FILE *fp;
fp = fopen(path, "wb");
if (fp == NULL) {
return -1;
}
len = strlen(write_string);
/* copy the file into the buffer: */
if (fwrite(write_string, 1, len, fp) != len) {
return -1;
}
if (fclose(fp) == EOF) {
return -1;
}
return 0;
}
/*
writes an array of ints to a file
ints are space separated, with a trailling space
on errror, returns, -1, succes 0
*/
int write_int_arr_file(char * path, int *arr, int len) {
int i;
FILE * fp = fopen(path,"w");
if (fp == NULL) {
return -1;
}
for(i=0; i<len; i++){
if (fprintf(fp,"%d ", arr[i]) < 0){
return -1;
}
}
if (EOF == fclose (fp)){
return -1;
}
return 0;
}
/* Same as int, saved in exp notation, */
/* with precision (deciamal places) precision */
int write_float_arr_file(char * path, float *arr, int len, int precision) {
int i;
FILE * fp;
fp = fopen(path,"w");
if (fp == NULL){
return -1;
}
for(i=0; i<len; i++){
/*if (fprintf(fp,format, arr[i]) < 0){*/
if (fprintf(fp,"%.*e", precision, arr[i]) < 0){
return -1;
}
}
if (EOF == fclose (fp)){
return -1;
}
return 0;
}
/* +1 for the null char */
#define PRIxPTR_WIDTH ((int)(sizeof(void*)*2))
/* Process address space. */
int BSS;
int DATA = 1;
int post_inc_global() {
global++;
return global - 1;
}
int asm_precalc(int i) {
return i + 1;
}
int asm_precalc_inline(int i) {
return i + 1;
}
/*
#exit
Exit program at any point, including outside of the main function.
Gets return value as an argument.
*/
void exit_func() {
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}
void atexit_func() {
printf("atexit\n");
printf("ALL ASSERTS PASSED\n");
}
/*
#abort
man abort
Sources:
- <http://stackoverflow.com/questions/397075/what-is-the-difference-between-exit-and-abort>
- <http://stackoverflow.com/questions/3676221/when-abort-is-preferred-over-exit>
Differences from exit:
- does not call `atexit` function.
- raises `SIGABRT`
- does not call C++ destructors
*/
void abort_func() {
abort();
}
/*
# main
# Call main from the program
Seems legal:
http://stackoverflow.com/questions/13948562/recursion-using-main-function#comment19237980_13948579
Illegal in C++ however.
# main signature
- http://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c
- http://stackoverflow.com/questions/4207134/what-is-the-proper-declaration-of-main
Valid signatures: either:
int main()
or
int main(int argc, char* argv[])
Or equivalent ones to the above:
TODO name of equivalend:
int main(int argc, char** argv)
Default return type `int` (C89 only):
main()
Explicit `void` prototype:
int main(void)
*/
int main(int argc, char **argv) {
/*
Comments.
*/
{
/* Standard multi line comment. */
/*
assert(false);
*/
/* A comment may contain `/ *`, but GCC warns with `-Wcomment`. */
#if __STDC_VERSION__ >= 199901L
/* Double slash comment like in C++ were only introduced in C99. */
/*assert(false);*/
#endif
}
/*
# Identifiers
Identifiers are names either for variables,
functions, structs, enums, unions, macros, ...
*/
{
/*
# scope of identifiers
Every pair of braces, or constructs that uses braces such as `if`
create a new scope
You may define variables in that scope with the same names as external ones,
but if you do so the external ones will become completely invisible
*/
{
{
{
int i = 0;
/* ERROR redeclaration. */
/*int i; */
{
assert(i == 0);
/*
From now on, it is impossible to access the outer `i`
from the inner scope.
*/
int i = 1;
assert(i == 1);
}
assert(i == 0);
}
/*
# Dangling pointer from block scope
Undefined behavior: there is no guarantee that a variable declared in a scope outlives
that scope, even if there are pointers pointing to it. C does not track how many pointers
there are to a given variable.
http://stackoverflow.com/questions/2759371/in-c-do-braces-act-as-a-stack-frame
*/
{
int *ip;
{
int i = 1;
ip = &i;
}
/* BAD: undefined behaviour */
/*assert(*ip == 1);*/
}
/*
Undefined behaviour, because the rhs `i` is already the inner i
*/
{
int i = 1;
{
int i = i;
/*assert(i == 1);*/
}
}
}
}
/*
# namespaces
Not like the C++ concept.
C puts the following identifiers in different namespaces:
- tags of: enums, structs, and union
- labels of goto
- fields of structs
- the rest: called *ordinary identifiers*: variable, function names
For this reason you can use the identifier name in the same scope
as long a they are in different namespaces.
In C++, tags are put in the same namespace as variables.
*/
{
/*
Tag and ordinary identifier.
*/
{
struct s {int i;};
int s;
}
/* Both ordinary identifiers. */
{
int same_name_as_variable = 0;
/* ERROR: called object is not a function: */
/*same_name_as_variable();*/
assert(same_name_as_variable == 0);
}
}
/*
Names of identifiers
*/
{
/*
Allowed identifiers follow the regex: _[a-Z0-9_]*
*/
{
/* ERROR name cannot start with digit. */
/*int 0a;*/
}
/*
# Keywords
# Reserved identifiers
Keywords are identiers which have a special meaning in the language like `for` or `if`.
You cannot use those in your variables.
Full list:
_Alignas auto extern short
_Alignof break float signed
_Atomic case for sizeof
_Bool char goto static
_Complex const if struct
_Generic continue inline switch
_Imaginary default int typedef
_Noreturn do long union
_Static_assert double register unsigned
_Thread_local else restrict void
enum return volatile
while
C99 specifies that:
> All identifiers that begin with an underscore and either an uppercase letter
or another underscore are always reserved for any use.
> All identifiers that begin with an underscore are always reserved
for use as identifiers with file scope in both the ordinary and tag name spaces.
TODO what does `identifiers with file scope` mean?
POSIX adds many further per header reserved names which it would be wise to follow even on ANSI C:
<http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html> section "The Name Space".
The following compile for now, but may break in any future version of the standard if they define them as keywords.
The following identifiers used the above rules:
- introduced in C99:
- `_Bool`
- `_Complex`
- `_Imaginary`
- introduced in C11:
- `_Alignas`
- `_Alignof`
- `_Atomic`
- `_Generic`
- `_Noreturn`
- `_Static_assert`
- `_Thread_local`
*/
{
int _not_yet_a_keyword;
int _Not_yet_a_keyword;
int __not_yet_a_keyword;
}
/*
Standard seems to say nothing of this edge case, since `_` is not followed by any letter TODO confirm
Still, it would be very cryptic to use such an identifier
(although it is used it is used in Django internationalization and the Underscore Javascript library...)
*/
{
int _;
}
}
}
/*
# Basic types
Types like `int`, `char`, `float` and `_Complex`.
# Derived types
Types which are not based, bur defined by users,
e.g., arrays, structs and unions.
*/
/* # variables */
{
{
int i;
i = 5;
}
{
int i = 5;
int j = 7;
}
/* 31 bit + 1 sign bit integer */
{
int i = 5, j = 7;
}
}
/*
# Literals
*Literals* are values that can be expressed through a single
language dedicated feature:
- int: `1`
- long: `1L`
- float: `1.0f`
- double: `1.0`and their
- char: `'a'`
- string: `"abc"`
Some base types do not have specific literals: e.g. `short`.
C99 introduces compound literals, which allow creation of literals for
- arrays
- structs
- unions
*/
{
#if __STDC_VERSION__ >= 199901L
/*
# compound literals
Before C99 there were no literals for arrays, structs or unions,
while literals existed for ints, chars and even strings (which are arrays of chars...)
Compound literals are exactly that: literals for types that are made up of many smaller
pieces, thus compounded.
Great source: <www.drdobbs.com/the-new-c-compound-literals/184401404>
*/
{
/* Compound literals for arrays */
{
int *is;
is = (int[2]){ 0, 1 };
assert(is[0] == 0);
assert(is[1] == 1);
/* Reassign is to a new array. */
/* Old memory becomes innacessible. */
is = (int[2]){ 2, 3 };
assert(is[0] == 2);
assert(is[1] == 3);
/* The effect is the same as `int is[] = { 1 }`, */
/* that is: fill with zeroes. */
is = (int[2]){ 1 };
assert(is[0] == 1);
assert(is[1] == 0);
/* Major application: pass initialized arrays and structs to functions. */
{
func_array((int[]){ 1 });
func_struct_1((struct func_struct){ .i = 1 });
}
}
/*
Compound literals yield lvalues.
It is possible to take the address of compound literals.
Unlike string literals, array literals can be modified.
This means that the compound literal is an unnamed stack variable,
and takes stack space.
*/
{
int *ip;
ip = &(int){1};
ip[0]++;
assert(*ip == 2);
}
/* Int useless examples */
{
int i;
i = (int){1};
assert(i == 1);
i = (int){1} + (int){1};
assert(i == 2);
/* Any expression is fine */
{
i = 0;
i = (int){i + 1};
assert(i == 1);
}
}
/*
Scope of compound literals.
Just like for normal variable declaration,
compound literal memory can only be accessed in the scope in which it is declared.
<http://stackoverflow.com/questions/14955194/lifetime-of-referenced-compound-array-literals>
*/
{
int *p;
{
p = (int[]){1, 2};
assert(p[0] == 1);
}
/* BAD *p is undefined. */
/*assert(p[0] == 1);*/
}
}
#endif
}
/*
# types
*/
{
/*
# Integer types
# Integer literals
Types that represent integer numbers are called integer types.
This classification is explicitly used on the C specification,
some operations or rule of the c language are only valid for integer types,
while others work also for floating point types.
`char` is also an integer type
*/
{
/* # char */
{
/* char has fixed size 1 byte: */
assert(sizeof(char) == 1);
/* char literals are specified by single quotes */
{ char c = 'a'; }
/* Char literals can be cast to integers by replacing them with */
/* their corresponding ascii integer value for example, 'a' == 97: */
assert('a' == 97);
/*
WARN: multi-character character literals are obscure valid code, but the
byte ordering is undefined, so they are rarelly useful, and should be avoided.
gcc raises 4.8 warnings on -pedantic.
*/
/* assert('ab' == 'ab'); */
/*
char literals can contain any byte even those which have
no corresponding ASCII value such as say, `130`.
To get those literal values, the only way is to typecast from `int` as:
*/
{ char c = (char)130; }
/* Possible via escape sequences are like in strings. */
assert(((int)'\n') == 0x0a);
assert(((int)'\'') == 0x27);
/* TODO how to make a literal backslash char? */
}
/*
# short
Short has no specific literals, the only way is to typecast.
*/
{
{ short si = 1; }
{ short si = (short int)1; }
{ int i = 1; }
/* Lower case possible but bad, since l looks more like 1 than `L`.*/
{ long li = (long)1l; }
{ long li = (long)1L; }
}
#if __STDC_VERSION__ >= 199901L
/* # long long int */
{
{ long long lli = 8ll; }
{ long long lli = 8LL; }
}
#endif
/* ERROR: mixed cases not allowed */
/*{ long long lli = 8Ll; }*/
/* Short, long and long long are the same as the int versions: */
assert(sizeof(short) == sizeof(short int));
assert(sizeof(long) == sizeof(long int));
assert(sizeof(long long) == sizeof(long long int));
/* Unsigned: */
{
{ unsigned char uc = (unsigned char)1; }
{ unsigned short usi = (unsigned short int)1u; }
{ unsigned int ui = 1u; }
{ unsigned int ui = 1U; }
{ unsigned long uli = 1lu; }
{ unsigned long uli = 1LU; }
{ unsigned long long ulli = 1llu; }
{ unsigned long long ulli = 1LLU; }
/* The following are not recommended unless you are into code obfsucation: */
{ unsigned long uli = 1Lu; }
{ unsigned long uli = 1lU; }
{ unsigned long long ulli = 1LLu; }
{ unsigned long long ulli = 1llU; }
/* ERROR: */
/*{ unsigned long long ulli = 1Llu; }*/
}
/* # Bases for integer literals */
{
/* # Hexadecimal */
{
assert(16 == 0x10 );
assert(16 == 0x10 );
assert(16 == 0x10l );
assert(16 == 0x10ll );
assert(16 == 0x10u );
assert(16 == 0x10ul );
assert(16 == 0x10ull);
/* Case does not matter. */
assert(0xaB == 0xAb );
}
/* Octal. */
{
assert(16 == 020);
}
/*
# Binary literals
No ANSI way, but exist as a GNU extension.
<http://stackoverflow.com/questions/18244726/why-doesnt-c-have-binary-literals>
*/
}
/*
# Integer representation
C does not fix the binary representation for signed integers,
it only states which properties represenations must have.
As an example, the C standard explicitly mentions that the following
representations (but there may be more) are compatible with the standard:
- 2s complement
- 1s complement
- signed magnitude
Unsigned representation however seems to be fixed at the canonical binary.
This is what allows bitmasks to work.
<http://stackoverflow.com/questions/12125650/what-do-the-c-and-c-standards-say-about-bit-level-integer-representation-and-m>
*/
}
/* # Floating point types */
{
float f = 1.23f;
/* 1 signal 23 number 8 exponent */
float f1 = 1.23e-10f;
float f2 = 1.f;
/* ERROR: there must be a dot */
/*float f = 1f;*/
{ double d = 1.23; }
{ long double ld = 1.23l; }
{ long double ld = 1.23L; }
#if __STDC_VERSION__ >= 199901L
/*
# float hex literal
E.g.:
0xA.8p10
Equals:
1010.1000 * 2^3 = 10.5 x 2^10
The exponent is given *in decimal*.
*/
{
assert(0xA.0p0 == 10.0);
assert(0xA.8p0 == 10.5);
assert(0x1.8p1 == 3.0);
assert(0x1.0p10 == 1024.0);
}
/* There is no octal float literal: */
{
/*float f = 01.2p3;*/
}
#endif
}
#if __STDC_VERSION__ >= 199901L
/*
# Boolean type
# _Bool
Aliased as `bool` in `stdbool.h`.
*/
{
_Bool b = 0;
}
#endif
#if __STDC_VERSION__ >= 199901L
#ifndef __STDC_NO_COMPLEX__
/*
# Complex types
# _Complex
Possibly added to C99 to help replace FORTRAN once and for all.
# Complex literals.
Not part of the language: defined in the stdlib. For this reason,
we have to cheat on complex literal together with the complex.h header.
# STDC_NO_COMPLEX
If defined the implementation may not have complex.h.
Therefore, it is possible to be compliant without it.
*/
{
{ float _Complex c; }
{ double _Complex c; }
{ long double _Complex c; }
/*
WARN: You must say `double _Complex` or `float _Complex`:
just `_Complex is not standard.
*/
{
/* _Complex c */
}
/*
# Complex integer types
Complex integer types are not specified in C.
GCC adds them as an extension.
*/
{
/*int complex zi = 1 + 1*I;*/
}
}
#endif
#endif
/*
# void type
Mysterious type with many unrelated use cases:
- indicate that a function returns nothing: `void f();`
- indicate that a function takes no arguments: `int f(void);`
- pointers that can be typecast to any type for polymorphism
*/
{
/* ERROR: variable or field declared void */
/*void v;*/
/* ERROR: invalid application of sizeof to void type */
/*printf("sizeof (void) = %d\n", sizeof(void));*/
}
}
/*
# sizeof
Language keyword.
Gives the size of the RAM representation of types **in multiples of CHAR_BIT**,
which is the size of `char`. *Not* necessarily in bytes.
The return type is `size_t.
Calculated at compile time.
# size_t
Typedef `size_t` to the data type that specifies data sizes in libc.
`size_t` is large enough to represent any array index.
Always use it in your code instead of `int` to have greater portability.
Can be printed in `printf` with `%zu`.
# Size of base types
Implementation-defined behaviour.
base types like int of float don't have fixed ANSI sizes: only a minimum value is specified.
so machines are free to take optimal values in terms of speed/storage
`char` is an exception as it has a fized size of one byte.
For most modifier os similar types (ex: short int, int, long, long long)
the ANSI also guarantees size inequalities (equality is possible)
# Fixed size types
Besides the base times with nonfixed sizes, c99 ANSI libc also furnishes
fixed sized types
You should only use those when having a fixed size is crucial,
otherwise just use the base C types which are optimized for speed
according to each architecture.
*/
{
size_t size = sizeof(int);
puts("sizeof (bytes):");
printf(" char = %zu\n", sizeof(char) );
printf(" int = %zu\n", sizeof(int) );
printf(" long int = %zu\n", sizeof(long int) );
printf(" long long = %zu\n", sizeof(long long) );
printf(" float = %zu\n", sizeof(float) );
printf(" double = %zu\n", sizeof(double) );
printf(" long double = %zu\n", sizeof(long double) );
printf(" wchar_t = %zu\n", sizeof(wchar_t) );
printf(" size_t = %zu\n", sizeof(size_t) );
/* char has fixed size: */
assert(sizeof(char) == 1 );
/* Size equality is always possible: */
assert(sizeof(short int ) <= sizeof(int ));
assert(sizeof(int ) <= sizeof(long int ));
assert(sizeof(long int ) <= sizeof(long long int ));
assert(sizeof(float ) <= sizeof(double ));
assert(sizeof(double ) <= sizeof(long double ));
/*
The following lower bounds are guaranteed.
http://stackoverflow.com/questions/1738568/any-guaranteed-minimum-sizes-for-types-in-c
*/
assert(sizeof(short int) >= 2);
assert(sizeof(long int) >= 4);
assert(sizeof(long long int) >= 8);
/* Unsigned does not change sizeof: */
assert(sizeof(unsigned int) == sizeof(int));
assert(sizeof(unsigned long int) == sizeof(long int));
}
/*
# Constant expressions
# Compile time constants
Defined in C99 6.6.
The fact that an expression is a compile time constant
or not has effects such as:
- when declaring an array, if the size is a constant expression
then the array is a regular aray, if not it is a VLA statring on C99,
or a compilation error before.
- only constant expressions can be used in `_Static_assert`
C++ does not allow const pointer typecasts, so `const` variables generate constant expressions.
There is an even more explicit language feature in C++11 via the `constexpr` keyword.
*/
{
}
#if __STDC_VERSION__ >= 201112L
/*
# Static_assert
# _Static_assert
Makes compile time assertions.
Can only take constant expressions (C99 6.6).
Issues warnings or prevents compilation if failed.
C++ has the analogous `static_assert`.
*/
{
/* ERROR: static assertion failed: "Error message". */
/*_Static_assert(0, "Error message.");*/
_Static_assert(1, "e");
_Static_assert(1 + 1, "e");
const int i = 1;
/* ERROR: expression in static assertion is not constant. */
/*_Static_assert(i, "e");*/
}
#endif
/*
# typecast
Transformation of one datatype to another.
Can be done either implicitly or explicitly via a typecast operator.
Some convertions may are allowed by the standard implicitly,
but generate compiler warnings when done implicitly because in practice
they should almost never be used.
Some convertions are not allowed by the standard
and should always generate compilation errors.
Typecasts only transform the data:
it seems that it is not possible to change the type of a variable itself:
<http://stackoverflow.com/questions/2822795/how-i-change-a-variable-of-a-type-to-another-one-in-c>
*/
{
/*
# Implicit typecasts done on operations
The standard specifies which operations generate which typecasts.
*/
{
/* On assignment, the value is cast to the type of the variable assigned to. */
{
int i;
/* A typecast to int is done because `i` is `int`. */
i = 0.1;
/* SAME: */
i = (int)0.1;
assert(i == 0);
}
/*
If an operation involves an integer type and a floating type,
TODO the integer type is cast to the floating type.
*/
{
assert(1/2 == 0);
assert(1/2.0 == 0.5);
/* Typecasts happen on the same order that the operations are evaluated. */
assert(2.0*(1/2) == 0.0);
assert((2.0*1)/2 == 1.0);
}
/*
If an operation involves a smaller integer type and a larget integer type
TODO the smaller type is first cast to the larger type
*/
{
assert((char)CHAR_MAX + 1 == ((int)(char)CHAR_MAX + 1));
}
}
/* Typecasts between integer and floating point types. */
{
/* float to int rounds towards 0. */
{
assert((int)0.5 == 0);
assert((int)-0.5 == 0);
}
/* int to float can cause loss of precision if the int does not fit */
/* in the fp mantissa. */
{
}
}
/* Typecast of a value outside of range is undefined behaviour */
/* (could return any value or raise any signal). */
if (0) {
unsigned char uc = 256;
char c = 1e1000;
}
/* Array to pointer of same type: */
{
int is[] = {0, 1, 2};
int *is2 = is;
assert(is2[0] == 0);
}
/*
# void typecast
It is however possible to cast any type to void.
But that cannot have any effect since you cannot set the result to a variable.
It can however be used to avoid unused variable warnings.
*/
{
/*
# Unused function arguments
- avoid compiler warnings
- document intent to developpers
<http://stackoverflow.com/questions/4647665/why-cast-an-unused-function-parameter-value-to-void>
Why would a function not use a parameter in real life:
- callbacks with fixed signature for which you don't need some parameters
- macros that can be turned on or off. In particular, remember that `assert()` is a macro
and can be toggled with `NDEBUG`.
*/
{
int i = 0;
(void)i;
i = 1;
}
/*
# Unused return value
- avoid compiler warnings
*/
}
/* # Impossible typecats */
{
/* Certain typecasts always generates compilation errors. */
/* Implicit pointer to int is impossible: */
/*
{
int* ip;
int i;
i = ip;
}
*/
/* Pointer to float is impossible even with explicit typecast: */
/*
{
int* ip;
float f;
f = (float)ip;
}
*/
/* Pointers of different types, */
/* even if types for which data can be converted like floats and doubles: */
/*
{
float* fp;
double* dp;
dp = fp;
}
*/
/* Array to array of different size: */
/*
{
int is1[1];
int is2[2];
is2 = (int[])is1;
}
*/
}
}
/*
# Overflow
Overflow has two meanings:
- mathemtaical definition: making an operation in which the result
is larger than the maximum value or smaller than the minimum value.
This is the more common meaning of the term *overflow* outside of this context.
In this section this will be called *mathematical overflow*.
There is no automatic overflow check on operations
except at initialization and assignment by constants
at compile time.
Operations that can overflow mathematically but never overflow include:
- unsigned integer sum or multiplication
- flag definition: raising the overflow FLAG on a x86 processor or analogous.
This is the meaning of overflow in the ANSI C definition.
Therefore, in this section this will be called simply *overflow*.
Overflow always implies undefined behaviour. This could include a program crash!
Therefore, is something overflows,
it just silently overflows, possibly causing a hard to find bug.
Operations that may overflow include:
- signed integer sum or multiplication
Since this kind of overflow modifies an observable processor state,
it is possible for compilers to detect this situation.
Flag overflow always implies mathematical overflow, but not the converse.
For instance, unsigned integer overflow never raises the overflow flag of an x86
processor: it just wraps around.
Therefore, unsigned integer multiplication never overflows.
# GCC overflow specifics
gcc 4.8 is smart enough to warn in many cases with `-Woverflow`:
which is part of `-Wall`. We have turned it off so it wont annoy us on our tests.
`-ftrapv` causes gcc to detect an overflow and raise a `SIGABRT`,
this making their behaviour defined.
*/
{
/* Integer overflow */
{
/* The same holds true for unsigned integer type. */
{
unsigned int ui;
ui = UINT_MAX + 1;
assert(ui == 0);
}
/* This could crash due to undefined behaviour. */
if (0) {
int i;
i = INT_MAX + 1;
printf("signed integer sum overflow = %x\n", i);
}
/* Detect if integer sum overflow would happen */
/* http://stackoverflow.com/questions/199333/best-way-to-detect-integer-overflow-in-c-c */
/* Unsigned multiplication does modulo: */
{
unsigned char uc = 255;
uc *= 2;
assert(uc == 254);
}
/* Signed multiplication undefined. */
/* This could crash due to undefined behaviour. */
if (0) {
char c = 0x8FFF;
c *= -2;
printf("char 0x8FFF * -2 = %x\n", c);
}
/* Detect if integer multiplication overflow would happen: */
/* http://stackoverflow.com/questions/1815367/multiplication-of-large-numbers-how-to-catch-overflow */
}
/* Floating point */
{
/* TODO what happens? how to detect? */
assert(1.00000000000000000000000000000000000000000000001 == 1.0);
}
}
/*
# Type qualifiers
Can be added to types to modify their semantics.
*/
{
/* Repeating qualifiers is OK and has no effect. C99 9.7.3.4 */
{
const const const const int i = 0;
/* In practice, this is more likely to happen when the qualifier is hidden on a typedef. */
{
typedef const int ci;
const ci i;
}
}
/*
# const qualifier
*/
{
int i = 0;
const int ic = 0;
/* Same. */
/*int const ic = 0*/
const int ic2 = i;
/*
BAD.
Legal and compiles without warning, but is bad since ic3 cannot get a value
unless you typecast its pointer with a warning.
consts should normally get a value at initialization time.
*/
const int ic3;
/* ERROR: assignment of read only variable ic. TODO Illegal or undefined?. */
{
const int ic = 0;
/*ic = 1;*/
}
/*
# Modify const through pointer cast
Casting a const to a non-const through a pointer is legal.
Modifying he const with the pointer is undefined behavior (C99 6.7.3.5).
For this reason it does not generate compile time constant expressions (C99 6.6):
the undefined behavior could be to change the value of the const.
In particular, existing implementaions may or may not put `const` in read only memory,
so that the undefined behavior may be a page fault.
`gcc` for examples puts global constants on the `.rodata` section of the elf output.
In practice It might work however for local function variables however,
which are just on the stack or registers.
Many compilers raise warnings or prevent compilation of such constructs.
In C++, discarding const is illegal, and generates compile time constants.
*/
{
const int ic = 0;
/*
WARN: initialization discards const qualifier from pointer type.
Likely to work since local variable.
*/
/*
int* ip = &ic;
*ip = 1;
assert(ic == 1);
*/
}
/*
# const pointers
There are 3 types of const pointers:
- `const X *` or `X const *` : cannot change the data of the thing pointer points to
- `X * const` : cannot change which thing the pointer points to
- `const X * const` or `X const * const` : both of the above
*/
{
/* const int * */
/* int const * */
{
int i = 0;
int j = 0;
const int *cip = &i;
int const *icp = &i;
/* Can change which opbject it points to. */
cip = &j;
icp = &j;
/* ERROR: const * prevents from changing the data of the object pointed to */
/**cip = 2;*/
/**icp = 2;*/
}
/* int * const */
{
int i = 0;
int j = 0;
int *const ipc = &i;
*ipc = 1;
assert(i == 1);
/* ERROR: cannot change what is being pointed to */
/*ipc = &j;*/
/*
# Single line declaration of multiple const pointers
Just like `*` must be repeated once per variable, `*const` must also be repeated.
*/
{
int i = 0;
int *const ipc2, *const ipc3, *ipcBad;
/* ^^^^^^ */
/* must repeat the `iconst` for each variable declared! */
i = 0;
ipcBad = &i;
*ipcBad = 1;
}
{
const int ic = 0;
/* WARN */
/* Initialization discards const. */
/* It would be possible to change the value of the const. */
/*int *const ipc = &ic;*/
/* BAD: we changed the value! */
/**ipc = 1;*/
}
}
const int* const cipc = &ic;
const int cis2[2] = { 1, 2 };
/* ERROR */
/*cis2[0] = 1;*/
/*
# const pointers to pointers
There are 7 possibilities at level 2 already!
To not mix up:
- const always applies to the pointer at its left.
- if there is no such pointer, it applies to the data
*/
{
int const ** icpp;
int * const * ipcp;
int ** const ippc;
int const * const * icpcp;
int const ** const icppc;
int * const * const ipcpc;
int const * const * const icpcpc;
}
/*
# add const is not possible
`const int * = int *` is possible, but it is not possible to do `const int ** = int **`.
This is a bit counter-intuitive at first since:
- we feel like we are adding a `const` qualifier increases restrictoins.
However, when it may lead to const modification, it is not acceptable.
- the phenomenon only appears at level 2 pointers to pointers, not with simple pointers
Similar considerations apply to the `volatile` qualifier.
<http://stackoverflow.com/questions/1468148/initialization-between-types-const-int-const-and-int-is-not-allowed-why>
*/
{
/* If `const int ** = int **` were possible then we could change constants. */
{
int* p = 0;
/* (1) THIS cannot be done: `const int ** = int **` */
/*int const** pp = &p; */
/*int const c = 123;*/
/* OK, &c is int const*, and *p is int const* lvalue. p points to c now! */
/**pp = &c;*/
/* OK: p is not const. We changed c! */
/**p = 666;*/
}
/* The problem only arises in multidimensional cases. */
/* Here it is impossible to change a const. */
{
int i = 0;
int const * p = &i;
}
}
}
/*
# const struct
*/
{
/*
The entire struct is const.
Members of a const struct cannot be modified.
*/
{
struct s { int i; };
const struct s s = { 1 };
/* ERROR */
/*s.i = 2;*/
}
/* Single members can be declared const. */
{
struct s {
int i;
const int j;
};
struct s s = { 0, 1 };
s.i = 2;
/* ERROR */
/*s.j = 2;*/
}
/* Entire structs cannot be declared const. */
{
/* WARN: useless type qualifier */
/*const struct s { int i; };*/
}
}
/*
# Return const from func
- <http://stackoverflow.com/questions/8716330/purpose-of-returning-by-const-value>
- <http://stackoverflow.com/questions/8406898/benefits-of-using-const-with-scalar-type-e-g-const-double-or-const-int?lq=1>
*/
{
/*
USELESS
There seem to be no noticeable effect of returning const for non pointer scalars.
*/
{
/*int_func();*/
/*const_int_func();*/
}
/*
For pointer types this has a noticeable effect
*/
{
/* OK */
{
int i = 0;
(*int_ptr_func_int_ptr(&i)) = 2;
assert(i == 2);
}
/* ERROR */
{
int i = 0;
/*(*const_int_ptr_func_int_ptr(&i)) = 2;*/
/*assert(i == 2);*/
}
}
/*
For structs this also has a noticeable effect.
In C++ however there can be noticeable effect
because the returned object may have a non-const function that changes it
so that the following is possible:
objFunc().nonConst();
but the following would not be:
constObjFunc().nonConst();
*/
{
/*struct_func*/
/*const_struct_func*/
}
}
#if __STDC_VERSION__ >= 199901L
/*
# const in array size function argument
Same effect as declaring `int *const`, but without cast to pointer.
*/
{
int is2[2];
is2[0] = 0;
const_array_size_argument(is2);
assert(is2[0] == 1);
}
#endif
}
#if __STDC_VERSION__ >= 199901L
/*
# restrict qualifier
Says to the compiler that every pointers passed to a function that is marked restrictd
does not refer to the same element.
Can only qualify pointers. The most common use case is to qualify pointers passed to functions.
Programmers must ensure that temselves. if they don't, undefined behaviour.
No behaviour change, but allows for further compiler optimization,
so it should be used whenever possible. See generated assembly to spot the difference.
Great example showing how restrict could help optimize things: <http://en.wikipedia.org/wiki/Restrict>
*/
{
{
int i = 0;
int j = 0;
int add = 1;
double_add(&i, &j, &add);
assert(i == 1);
assert(j == 1);
}
{
int i = 0;
int j = 0;
int add = 1;
restrict_double_add(&i, &j, &add);
assert(i == 1);
assert(j == 1);
}
/*
BAD: undefined behaviour, because the same pointer is passed twice
The compiler should be able to spot that one... but gcc 4.7 did not.
*/
{
int i = 1;
int j = 1;
restrict_double_add(&i, &j, &i);
if (i != 2)
printf("restrict i = %d\n", i);
if (j != 3)
printf("restrict j = %d\n", j);
}
/* OK: not restrict */
{
int i = 1;
int j = 1;
double_add(&i, &j, &i);
assert(i == 2);
assert(j == 3);
}
/* Outside functions. */
/* TODO what does it mean then? On the current */
{
int i;
int * restrict ip;
}
/* ERROR: can only qualify pointers */
/*int restrict ip;*/
}
#endif
}
/*
# static
The static keyword has many uses in C.
Multifile scope usage shall not be described here.
*/
{
/*
# static variable in functions
It is as if the variable were a global.
Use with caution:
- hard to understand
- not thread safe
*/
{
int i;
int si;
with_static_var(&i, &si);
assert(i == 1);
assert(si == 1);
with_static_var(&i, &si);
assert(i == 1);
assert(si == 2);
}
#if __STDC_VERSION__ >= 199901L
/*
# static in function argument array size
Specifies the minimum size of the array to be passed.
Can be used by the compiler for optimization
<http://stackoverflow.com/questions/3693429/c-parameter-array-declarators>
Not enforced by the compiler and does not alter any behaviour
except for the exact generated assembly code.
If the contract is not followed by the programmer, undefined behaviour.
*/
{
/* Undefined behaviour: */
int is2[2];
/*static_array_argument(is2);*/
int is4[4];
static_array_argument(is4);
}
#endif
}
/*
# automatic
Is the name for the default way to declare var
that is not volatile neither register.
Sadly, in C++11 is is something completely different: type inference.
*/
{
/* SAME: */
int i;
auto int i2;
/* ERROR: */
/*auto i3;*/
}
/*
# volatile qualifier
Compiler will not store this value in cpu registers or cache as speed optimization
instead of in RAM.
Applications:
- allow access to memory mapped devices
- allow uses of variables between setjmp and longjmp
- allow uses of sig_atomic_t variables in signal handlers.
- multithreading, where variable may to change value at any time on another thread.
For example on global scope:
int other_task_finished;
And on some function which must wait for another thread to finish a task:
other_task_finished = 0;
while(other_task_finished == 0){
yield();
}
If the value were stored in register, other threads in other processes may never see an update.
Concurrent operations on volatile variables are not guaranteed to be atomic.
Unfortunatelly, this cannot be demonstrated as of ANSI C99 since there is no multithread support.
*/
{
volatile int vi;
}
/*
# register
hint to compiler that ri be stored in register
instead of in RAM
not necessarily honored
almost always done without a hint if possible
*/
{
{
register int ri;
}
/* ERROR: cpu registers don't have addresses! */
{
register int ri;
/*int* ip = &ri;*/
}
/*
BAD: impossible to store compound types in registers
compiler will certainly not honor `register` hint
*/
{
struct S { int i; };
register struct S s;
}
}
/*
# typedef
Create new types based on old ones
On libc, the convention append `_t` to typedefs is used
ex: `size_t`, `wchar_t`, etc.
Some of those macros are defined to be strcitly integer types (like size_t)
while others can be either integer or floating points according to the implementation.
To print integer typedefs such with `printf`, see `printf`.
*/
{
{
typedef int Newint;
Newint i = 1;
assert(sizeof(Newint) == sizeof(int));
}
/* ERROR: unlike macros, typedef has scope just like that of variables: */
/*Newint i = 1;*/
/*
typedef position is very flexible.
Only use the first though if you want to be sane.
*/
{
typedef unsigned int uint;
unsigned typedef int vint;
unsigned int typedef wint;
/* This is the only one that fails: */
/*unsigned int xint typedef;*/
}
/*
Repeated typedef:
<http://stackoverflow.com/questions/8594954/repeated-typedefs-invalid-in-c-but-valid-in-c>
Allowed in C++ and C11, forbidden in C99.
*/
{
#if __STDC_VERSION__ >= 201112L
typedef int i;
typedef int i;
i j = 0;
#endif
}
}
#if __STDC_VERSION__ >= 201112L
#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 9
/*
# Generic
Compile time variable type inference!
*/
{
#define typename(x) _Generic((x), \
int: "int", \
float: "float", \
default: "other")
int i;
float f;
void* v;
assert(strcmp(typename(i), "int") == 0);
assert(strcmp(typename(f), "float") == 0);
assert(strcmp(typename(i), "other") == 0);
}
#endif
#endif
/*
# struct
Application:
- declare lots of data in one go
- pass lots of data in one go to functions
- avoid changing function signatures if you add a new field
to your struct.
*/
{
struct S {
int i;
float f;
};
/* Initialize by order. */
{
struct S s = { 1, 1.0 };
assert(s.i == 1);
assert(s.f == 1.0);
s.i = 2;
s.f = 2;
assert(s.i == 2);
assert(s.f == 2.0);
}
/* Define and initialize at the same time. */
{
struct S { int i; int j; } s0 = { 0, 1 }, s1 = { 2, 3 };
assert(s0.i == 0);
assert(s1.i == 2);
struct S s2 = { 4, 5 };
}
#if __STDC_VERSION__ >= 199901L
/*
# Designated initializer for structs
Allows to struc values by their name instead of order.
Sources:
- oracle tutorial with examples: <http://docs.oracle.com/cd/E19205-01/819-5265/bjazo/index.html>
*/
{
{
struct S s = {
.f = 1.0,
.i = 1
};
assert(s.i == 1);
assert(s.f == 1.0);
}
/* Can be mixed with array designated initializers. */
{
struct S { int a[2]; int i; };
struct S ss[] = {
[0].a = {0, 1},
[0].i = 2,
[1].a[0] = 3,
[1].a[1] = 4,
[1].i = 5
};
assert(ss[0].a[0] == 0);
assert(ss[0].a[1] == 1);
assert(ss[0].i == 2);
assert(ss[1].a[0] == 3);
assert(ss[1].a[1] == 4);
assert(ss[1].i == 5);
}
}
#endif
/*
# Empty struct
invalid, but possible as a GCC extension.
http://stackoverflow.com/questions/24685399/c-empty-struct-what-does-this-mean-do
*/
{
/*struct s {};*/
}
{
/* Assignment only works for initialization, unless use a C99 compound literal. */
{
struct S { int i; };
struct S s;
/*s = { 1 };*/
/*s = { .i = 1 };*/
}
/*
# Compound literals for structs
C99 compound literals allow to assign structs to struct literals.
*/
{
struct S { int i; int j; };
{
struct S s;
s = (struct S){ 1, 2 };
assert(s.i == 1);
assert(s.j == 2);
}
{
struct S s;
s = (struct S){ .j = 2, .i = 1 };
assert(s.i == 1);
assert(s.j == 2);
}
}
}
/* Pointer to struct. */
{
struct S s;
struct S* sp;
sp = &s;
/* equivalent `a->b` equals `(*a).b` */
sp->i = 1;
/*(*sp).i = 1;*/
assert(s.i == 1);
}
/* Array of structs initialization. */
{
struct S {
int i;
int j;
};
/* Non-designated. */
{
struct S ss[] = {
{ 0, 1 },
{ 2, 3 },
};
assert(ss[0].i == 0);
assert(ss[0].j == 1);
assert(ss[1].i == 2);
assert(ss[1].j == 3);
}
#if __STDC_VERSION__ >= 199901L
/* Designated. */
{
struct S ss[] = {
{ .j = 1, .i = 0 },
{ .j = 3, .i = 2 },
};
assert(ss[0].i == 0);
assert(ss[0].j == 1);
assert(ss[1].i == 2);
assert(ss[1].j == 3);
}
}
#endif
/*
Array fields
Array length must be specified.
Allocates that many objects of the given type.
*/
{
{
struct S
{
/* ERROR: */
/*int is[];*/
int is0[2];
int is1[2];
};
struct S s = { { 0, 1 }, { 2, 3 } };
assert(s.is0[0] == 0);
assert(s.is0[1] == 1);
assert(s.is1[0] == 2);
assert(s.is1[1] == 3);
/* Non-designated init. */
{
struct S ss[] = {
{ { 0, 1 }, { 2, 3 } },
{ { 4, 5 }, { 6, 7 } }
};
assert(ss[0].is0[0] == 0);
assert(ss[0].is0[1] == 1);
assert(ss[0].is1[0] == 2);
assert(ss[0].is1[1] == 3);
assert(ss[1].is0[0] == 4);
assert(ss[1].is0[1] == 5);
assert(ss[1].is1[0] == 6);
assert(ss[1].is1[1] == 7);
}
#if __STDC_VERSION__ >= 199901L
/* Designated init. */
{
struct S ss[] = {
{ .is0 = { 0, 1 }, .is1 = { 2, 3 } },
{ .is0 = { 4, 5 }, .is1 = { 6, 7 } },
};
assert(ss[0].is0[0] == 0);
assert(ss[0].is0[1] == 1);
assert(ss[0].is1[0] == 2);
assert(ss[0].is1[1] == 3);
assert(ss[1].is0[0] == 4);
assert(ss[1].is0[1] == 5);
assert(ss[1].is1[0] == 6);
assert(ss[1].is1[1] == 7);
}
#endif
}
/* Works for strings. */
{
struct S
{
char cs[3];
int i;
};
{
struct S s = { .cs = "ab", .i = 1 };
assert(strcmp(s.cs, "ab") == 0);
assert(s.i == 1);
}
{
struct S s = { "ab", 1 };
assert(strcmp(s.cs, "ab") == 0);
assert(s.i == 1);
}
/*struct S s = { "ab" };*/
}
}
/* Substructure init: it all works as expected. */
{
struct S1 { int i; int j; };
struct S0 { struct S1 s; };
/* Non-designated init. */
{
struct S0 s = { { 1, 2 } };
assert(s.s.i == 1);
assert(s.s.j == 2);
}
#if __STDC_VERSION__ >= 199901L
/* Designated init. */
{
struct S0 s = {
.s = {
.j = 2,
.i = 1
}
};
assert(s.s.i == 1);
assert(s.s.j == 2);
}
#endif
}
/*
# Incomplete types
Incomplete types are types which only have a declaration but no definition.
*/
{
/*
# struct that contains itself
# Incomplete type cycles
It is impossible to do the following, because that would create an infinite loop:
- each S contains one S. and one i.
- therefore the size of each S must be 2 ints:
size of S + size of int =
1 + 1 =
2
- but then the size of S must be 3 ints:
size of S + size of int =
2 + 1 =
3
- and so on
The solution is to store opaque pointers instead of the actual structs.
*/
{
/* ERROR: s has incomplete type. */
{
/*
struct S {
struct S s;
int i;
};
*/
}
/* ERROR: struct s1 undefined */
{
/*
struct S0 { struct S1 s1; };
struct S1 { struct S0 s0; };
*/
}
/* ERROR: s1 has incomplete type */
{
/*
struct S1;
struct S0 { struct S1 s1; };
struct S1 { struct S0 s0; };
*/
}
}
/*
# Opaque pointers
You can have pointers to incomplete types.
Forward declaration of S1 makes it makes it alright.
Such pointers are called opaque pointers.
<http://stackoverflow.com/questions/3854113/what-is-an-opaque-value>
A common usage pattern is:
- declare the opaque type in the .h file
- declare functions that use the opaque pointer in the .h file
- defined the type and the functions in the .c file
Now clients can only pass around pointers,
and use the type through the functions you give them,
but not access the fields they choose.
This is a way to implement private member variables in C.
`FILE` is widely used as an example of an opaque pointer, but it is not strictly opaque:
ANSI does not say that you cannot instantiate it, and popular implementations
have allowed that: ANSI only says nothing about it's fields,
so using them makes your code non-standard. TODO confirm.
*/
{
{
struct S1;
/* storage size of s isn't known . */
/*struct S1 s1;*/
struct S1* s1;
}
{
struct S1;
struct S0 { struct S1* s1; };
struct S1 { struct S0* s0; };
}
/*
The type itself has already been defined inside the struct definition,
so the following is fine.
*/
{
struct S { struct S* s; };
}
}
}
/* = Assigns fields one by one. */
{
struct S s = { 1, 1.0 };
struct S s2 = { 2, 2.0 };
s = s2;
assert(s.i == 2);
assert(s.f == 2.0);
}
/* equality `==` does not exist. There have been failed proposals. */
{
struct S { int i; };
struct S s = { 1 };
struct S s2 = { 1 };
/*assert(s == s2);*/
}
/*
Inequalities do not exist either: `<` `>` `<=` `>=`
Possible rationale: if `s.a < s2.a` and `s.b > s2.b`, what does `s < s2` eval to?
*/
/*
struct size
the way data is packed in a struct is not specified in the standard
common compiler strategy: align data to 32 bits
which makes acess faster, using slightly more memory
*/
{
struct S {
char c;
int i;
};
/* likelly to be 8 on a 2013 32 bit machine: */
printf("struct sizeof = %zu\n", sizeof(struct S));
assert(sizeof(char) + sizeof(float) <= sizeof(struct S));
}
/*
# Unnamed struct
This is a different concept than *anonymous structs*!!
<http://stackoverflow.com/questions/14248044/are-anonymous-structs-standard-and-really-what-are-they>
It is possible to create structs which don't have a name.
Only the structs declared immediatiely after definition can be used.
In theory only standardized in C11, but I am yet to be able to make GCC generate a warning.
even with `-std=89 -pedantic -Wall`.
<http://stackoverflow.com/questions/14248044/are-anonymous-structs-standard-and-really-what-are-they>
*/
{
/* Basic. */
{
struct { int i; int j; } s;
s.i = 0;
assert(s.i == 0);
}
/* Initialize. */
{
struct { int i; int j; } s = {0, 1};
assert(s.i == 0);
assert(s.j == 1);
}
/* Initialize array good style. */
{
struct { int i; int j; } s[] = {{0, 1}, {2, 3}};
assert(s[0].i == 0);
assert(s[0].j == 1);
assert(s[1].i == 2);
assert(s[1].j == 3);
}
/*
Initialize array bad style.
Generates a warning on GCC 4.7 and is horrible to read.
*/
{
/*struct { int i; int j; } s[] = { 0, 1, 2, 3 };*/
/*assert(s[0].i == 0);*/
/*assert(s[0].j == 1);*/
/*assert(s[1].i == 2);*/
/*assert(s[1].j == 3);*/
}
#if __STDC_VERSION__ >= 201112L
/*
# Anonymous substructure and union
Different from unnamed struct!
<http://stackoverflow.com/questions/14248044/are-anonymous-structs-standard-and-really-what-are-they>
Is an unnamed struct inside another struct.
Is / was also the non-standard name given to some concept.
TODO application?
*/
{
struct S {
int i;
struct {
int j;
int k;
};
};
/* ERROR: missing braces */
/*struct S s = {1, 2, 3};*/
struct S s = {1, {2, 3}};
assert(s.i == 1);
assert(s.j == 2);
assert(s.k == 3);
}
#endif
}
/*
# typedef struct combo
Advantages:
- avoid typing struct all over
- if in the future you decide to change a struct
with many boolean flags for an integer, you can do it.
- write the identifier only 2 times instead of 3
- put all declaration information into one single place.
No more: should the typedef be before or after doubts.
TL;DR best practice: whenever possible use:
typedef struct {} S;
Unfortunately this cannot be done if you need to declare the struct elsewhere to:
- you use a pointer to a struct of the same type inside it.
E.g.: linked lists.
In that case, use:
- use the declaration across many files. The typedef declaration would go into a `types.h`,
and the definition on a `precise-topic.h`.
*/
{
/*
The typedef can come before the struct.
*/
{
typedef struct S T;
struct S {
int i;
};
struct S s = {1};
T t = {1};
assert(s.i == t.i);
}
/*
You can typedef and declare the struct in a single statement.
*/
{
typedef struct S {
int i;
} T;
/* Same as: */
/*
typedef struct S T;
struct S {
int i;
};
*/
T t = {1};
T* tp = &t;
assert(tp->i == 1);
struct S s = {1};
struct S* sp = &s;
assert(sp->i == 1);
}
/*
The typedef and the struct can have the same name.
So the common C89 pattern is `typedef struct S {...} S`.
C11 adds anonymous structs which is even better.
*/
{
typedef struct S {
int i;
} S;
struct S ss = {1};
S s = {1};
assert(ss.i == s.i);
}
/*
# typedef to an unamed struct
- type even less than for typedef struct
- prevent anyone from using the useless `struct S`
- DRYer
*/
{
{
typedef struct {
int i;
} TypedefUnnamed;
TypedefUnnamed s = {1};
TypedefUnnamed* sp = &s;
assert(sp->i == 1);
/* ERROR: storage size of `t` isn't known. */
/* Same error as when the struct is not defined. */
/* Awesome, users cannot shoot themselves on the foot! */
/*struct TypedefUnnamed t;*/
}
/* Does not work either if the typedef is needed inside the definition. */
{
/*
typedef struct {
TypedefUnnamed* other;
} TypedefUnnamed;
*/
/* In that case you need: */
{
typedef struct TypedefUnnamed TypedefUnnamed;
struct TypedefUnnamed {
TypedefUnnamed* other;
};
}
/* Or: */
{
typedef struct TypedefUnnamed {
struct TypedefUnnamed* other;
} TypedefUnnamed;
}
/*
TODO possible to make it work such that it is impossible to say `struct s`,
like with unnamed structs?
*/
}
}
}
/*
# bitfields
Gives support for fields which contain a single bit in the language.
*/
{
struct S {
unsigned b1 : 1;
unsigned b2 : 2;
unsigned b3 : 3;
/* padding untill next int is added automatically because */
/* next data is not a bitfield and accesses is faster if it is aligned */
int i;
unsigned b4 : 1;
/* manually adds padding untill next field */
/* even if it is a bitfield */
unsigned : 0;
unsigned b5 : 1;
} s ;
assert(sizeof(struct S) == 16);
s.b1 = 1;
assert(s.b1 == 1);
/* WARN */
/* overflow */
/* truncate */
/*s.b1 = 2;*/
int i = 2;
s.b1 = i;
assert(s.b1 == 0);
/* Only takes lsb. */
i = 3;
s.b1 = i;
assert(s.b1 == 1);
}
/*
# offsetof
get distance of member variable from the start of the struct
appliction: get the struct that corresponds to a given pointer to a field.
this is used in the kernel via `container_of`, and can be used to implement
linked lists in ANSI c: <http://stackoverflow.com/questions/10269685/kernels-container-of-any-way-to-make-it-iso-conforming>
*/
{
struct foo {
char a;
char b[2];
int c;
char d;
};
printf("offsetof(struct foo, a) = %zu\n", offsetof(struct foo, a));
printf("offsetof(struct foo, b) = %zu\n", offsetof(struct foo, b));
printf("offsetof(struct foo, c) = %zu\n", offsetof(struct foo, c));
printf("offsetof(struct foo, d) = %zu\n", offsetof(struct foo, d));
}
}
/*
# union
Like struct, but all fields share the same data space.
If there are several data sizes, the struct has the size of the largest.
TODO applications: <http://stackoverflow.com/questions/4788965/c-c-when-would-anyone-use-a-union-is-it-basically-a-remnant-from-the-c-only>
*/
{
{
union U {
int i;
int j;
} u;
u.i = 0;
u.j = 1;
assert(u.i == 1);
}
}
/*
# Order of evaulation of arguments
The order of evaluation for expressions that are arguments
of functions or operators is unspecified behaviour.
For example, it is unspecified behaviour in
`f1() * f2()` if `f1` or `f2` is evaluated first,
which may matter if they have side-effects.
The same goes for `g(f1(), f2())`.
Also note that there is a further separation between evaluation (getting the value to pass forward),
and side effects which this evaulation may have (increasing `i` on an `i++`).
See sequence point` for that.
# Sequence point
<http://stackoverflow.com/questions/10782863/what-is-the-correct-answer-for-cout-c-c>
<http://stackoverflow.com/questions/3575350/sequence-points-in-c>
<http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points>
Some language features force side effects of an expression evaluation
to happen before continuing while others don't.
A typical example of a side effect is the increment of `i` on `i++`,
being the main effect the returning of the value of `i` before the increment.
Sequence points are the operations which enforce order of evaulation.
A full list is given here: <http://en.wikipedia.org/wiki/Sequence_point>
Since operators such as `*` or `+` are not on the sequence point list,
it is undetermined behaviour in `f1() * f2()` if `f1` or `f2` is evaluated first.
The same goes for `-`, `/` and the evaulation of arguments of a function.
Other operators however do create sequence points, for example the comma operator.
In simple cases, gcc 4.7 is smart enough to notice undefiened behaviour and emmits a warning.
This warning has been ignored for test purposes by a test only `-Wno-sequence-point` flag.
*/
{
/*
Undefined behaviour.
`=`does not create sequence points, to it is not possible to know if the side effect of `++`
will happen before or after the assigment.
Therefore, it is possible that this gives either:
post_increment_return = 0;
i = post_increment_return;
i++;
or
post_increment_return = 0;
i++;
i = post_increment_return;
*/
{
int i = 0;
i = i++;
printf("i = i++ = %d\n", i);
assert(i == 0 || i == 1);
}
/*
Defined behaviour because the return statement
guarantees that all side effects have happened.
Contrast with `i = i++`, which has no return statement.
*/
{
global = 0;
global = post_inc_global();
assert(global == 0);
}
/*
`+` does not specify a sequence point between its two sides.
Therefore, the side effect of either `++` (incrementing i) may or may not happen before the other `++` is evaluated.
This allows for the following outputs:
0 + 0 (neither side effect happened before the other)
1 + 0 or 0 + 1 (one side effect happened before the other)
*/
{
int i = 0;
int j = i++ + i++;
printf("i++ + i++ = %d\n", j);
assert(j == 0 || j == 1);
}
/*
Undefined behaviour.
The return statements are full expressions,
so they guarantee that either one or the other function call happens first.
However, it is not possible to know which side of `-` is evaulated first.
Ouptput depends on evaulation order, giving either:
0 - 1 = -1
if the first `post_inc_global()` is evaluated first or
1 - 0 = 1
if the second `post_inc_global()` is evaluated first.
*/
{
global = 0;
int j = post_inc_global() - post_inc_global();
printf("post_inc_global() - post_inc_global() = %d\n", j);
assert(j == -1 || j == 1);
}
/*
Defined behaviour because of the commutativity of addition and because the return statements guarantees
that all side effects are done with.
Constrast with `++global + ++global`, which is undefined because there are no return statements.
This may give either:
0 + 1 = 1
or
1 + 0 = 1
so both are the same by coincidence.
*/
{
global = 0;
assert(post_inc_global() + post_inc_global() == 1);
}
/*
Comma operator introduces a sequence point.
*/
{
int i = 0;
assert((i++, i++) == 1);
}
/* declarators in declarator sequence instroduce sequence points */
{
int i = 0, j = i;
assert(j == 0);
}
/*
Boolean operators `||` and `&&` introduce a sequence point.
*/
{
/*
The following happens:
- the first i++ returns 0
- since this is false, the second side is evaulated
- since `||` adds a sequence point, the increment side effect must happen
- i now equals one, and `||` evals true
*/
{
int i = 0;
assert(i++ || i);
}
/* same as for `||` */
{
int i = 1;
assert(! (i-- && i));
}
}
}
/* # Operators */
{
/*
# Arithmetic operators
Always be on the lookout for overflows. Rockets have fallen because of them.
*/
{
/*
# Sum
# +
*/
{
/* Basic example. */
assert((1 + 2) == 3);
/* TODO what happens on overflow? */
}
assert((2 * 3) == 6);
/*
# Division
Division is the most complex of the basic operations.
Integer division and floating point division are different
operations, which translate to different CPU instructions!
Remember that if an operation involves a floating point and an integer,
C first casts the integer type to a floating point type, then does
the floating point operation.
Division by `0` leads to different problems, which are also different
on the floating point and integer cases.
# INT_MIN / -1
`INT_MIN / -1` is undefined in 2's complement,
and 2's complement is explicitly said to be compliant to the C
integer representation standard.
*/
{
assert((4 / 2) == 2 );
/* integer division */
assert((1 / 2) == 0 );
/* floating poitn division */
assert((1.0 / 2.0) == 0.5);
/* floating poitn division. `1` is cast to `double` point */
assert((1 / 2.0) == 0.5);
/* same as above */
assert((1 / (double)2) == 0.5);
}
/* # Unary minus */
{
/*
Unary minus can overflow for the smallest negative number!
TODO example.
*/
}
/*
# Modulus
# %
*/
{
assert((3 % 3) == 0);
assert((4 % 3) == 1);
assert((5 % 3) == 2);
assert((6 % 3) == 0);
}
/* # Comparison operators */
{
assert((1 == 1) == 1);
assert((0 == 1) == 0);
assert((0 > 1) == 0);
assert((0 > 0) == 0);
assert((0 > -1) == 1);
assert((0 < 1) == 1);
assert((0 < 0) == 0);
assert((0 < -1) == 0);
assert((0 >= 1) == 0);
assert((0 >= 0) == 1);
assert((0 >= -1) == 1);
assert((0 <= 1) == 1);
assert((0 <= 0) == 1);
assert((0 <= -1) == 0);
}
}
/*
# Boolean operators
The boolean operators treat all integers as:
- 0: false
- != 0: true
The output of the boolean operators is always either 0 or 1.
*/
{
/*
# !
# Negation
*/
{
assert((!0) == 1);
assert((!1) == 0);
assert((!2) == 0);
assert((!-1) == 0);
/*
`x == 0` is equivalent to `!x`.
But its likely more readable to use `== 0` when doing comparisons,
and to leave `!x` just for boolean operations.
*/
}
/*
# ||
# or
*/
assert((0 || 0) == 0);
assert((0 || 1) == 1);
assert((1 || 0) == 1);
assert((1 || 1) == 1);
/*
# &&
# and
*/
assert((0 && 0) == 0);
assert((0 && 1) == 0);
assert((1 && 0) == 0);
assert((1 && 1) == 1);
/*
# Short circuit evaluation
For operators `||`, `&&` and `?`, the second side is only evaluated if needed.
On this example:
- 1 is evaulated to true
- || does not need to go any further, so i++ is not evaluated
Those operators also define sequence points.
*/
{
int i = 0;
1 || i++;
assert(i == 0);
1 && i++;
assert(i == 1);
}
}
/* # Bitwise operators */
{
/*
# ~
# NOT bitwise
*/
assert((~(char)0x00) == (char)0xFF);
assert((~(char)0xFF) == (char)0x00);
/*
# &
AND bitwise
*/
{
assert(((char)0x00 & (char)0x00) == (char)0x00);
assert(((char)0xFF & (char)0x00) == (char)0x00);
assert(((char)0xFF & (char)0xFF) == (char)0xFF);
/*
# Even
# Odd
# Find if number is even or odd
http://stackoverflow.com/questions/160930/how-do-i-check-if-an-integer-is-even-or-odd
This is another "application" of `&`.
But seems to be as fast as `%`, and is definitely less readable.
*/
{
assert((3 & 1) == 1);
assert((4 & 1) == 0);
}
}
/*
# ||
# OR bitwise
*/
assert(((char)0x00 | (char)0x00) == (char)0x00);
assert(((char)0xFF | (char)0x00) == (char)0xFF);
assert(((char)0xFF | (char)0xFF) == (char)0xFF);
/*
# ^
# XOR bitwise
*/
assert(((char)0x00 ^ (char)0x00) == (char)0x00);
assert(((char)0xFF ^ (char)0x00) == (char)0xFF);
assert(((char)0xFF ^ (char)0xFF) == (char)0x00);
/*
# bitmask
The major aplication of bitwise operators it making masks to:
- set: MASK &
- reset
- toggle
- retrieve
bits from unsigned integer fields.
These exist to allow to use one bit to store one bit,
because the minimal addressable unit on computers is 8 bits.
While such operators exist in almost all languages,
they are much more common in low level languages like C
where optimization is more present.
Only work because C fixes the binary representation of unsigned integers.
*/
/*
# <<
# >>
# Shift operators
Low level bit shifting.
For the right input, the result would
depend on which integer representation is being used,
which is not fixed by the C standard.
*/
{
assert((1u << 0u) == 1u);
assert((1u << 1u) == 2u);
assert((1u << 2u) == 4u);
assert((1u << 3u) == 8u);
assert((8u >> 0) == 8u);
assert((8u >> 1) == 4u);
assert((8u >> 2) == 2u);
assert((8u >> 3) == 1u);
assert((8u >> 4) == 0u);
assert((5u >> 1) == 2u);
/*
Undefined behaviour occurs if any of the inputs is signed.
For the LHS, it is likely because the integer representation is undefined.
*/
{
/*printf("2u << -1 = %d\n", 2u << -1);*/
/*printf("-1 << 1u = %d\n", -1 << 1u);*/
}
/*
# Binary operator on floating point numbers
Fun, but not possible.
http://stackoverflow.com/questions/1723575/how-to-perform-a-bitwise-operation-on-floating-point-numbers
*/
{
/*1.2 << 1;*/
}
}
}
/*
# assign
*/
{
{
int i = 0;
i = 1;
assert(i == 1);
}
/*
= returns rvals
*/
{
int i;
assert((i = 1) == 1);
/*
This is why this works (and probably why it is made behave like this.
*/
{
int i, j, k;
i = j = k = 1;
/*i = (j = (k = 1));*/
assert(i == j && j == k && k == 1);
}
}
/*
# self assign initialization
Good old undefined behaviour through innocent statements.
<http://stackoverflow.com/questions/11186261/why-is-int-i-i-legal>
*/
{
int self_assign_init = self_assign_init;
printf("self_assign_init = %d\n", self_assign_init);
}
/*
# lvalue
Something that can be on the left side of an assign, such as a variable.
Every lvalue is a rvalue.
# rvalue
Something that can only be used on the right side of an assign,
but not on the left side.
*/
{
/*
In C, assign does not return lvalues.
In C++ it does.
*/
{
int i = 0, j = 1, k = 2;
/*(i = j) = k;*/
}
/*
Function returns are rvalues.
In C++, this has an exception: functions that return references return lvalues
*/
{
/*int_func_int(1) = 1;*/
/*struct_func().i = 1;*/
}
/*
A dereferenced pointer becomes an lvalue.
*/
{
int i = 0;
(*int_ptr_func_int_ptr(&i)) = 2;
assert(i == 2);
}
}
}
/*
# Increment
# Pre-increment vs post-increment
<http://stackoverflow.com/questions/24886/is-there-a-performance-difference-between-i-and-i-in-c>
Which is faster?
- in c, equal
- in c++, ++i potentially if i is a complex object
# Why the increment operator exits
Why it exists if equivalent to x=x+1?
Because there is an x86 instruction for that
Why?
- because it takes less program memory `inc eax`, instead of `sum eax,1`
- and is a *very* common instruction
What about +=, -=, etc. ?
Same thing: `ax = ax + bx` == `sum ax,bx`
*/
{
int i;
i = 0;
assert(i++ == 0);
assert(i == 1);
i = 0;
assert(++i == 1);
assert(i == 1);
i = 1;
assert(i-- == 1);
assert(i == 0);
i = 1;
assert(--i == 0);
assert(i == 0);
/*
Also works for floating point,
although the usage is much less common.
*/
double f = 0.5;
assert(f++ == 0.5);
assert(f == 1.5);
}
/*
Composite operators
Do an operation and an assign at the same time.
Exist for many operators.
Why do they exist? Assemby support probably,
as many assembly operations overwrite one of the operands.
*/
{
int i;
i = 0;
assert((i += 1) == 1);
assert(i == 1);
i = 1;
assert((i -= 1) == 0);
assert(i == 0);
i = 1;
assert((i *= 2) == 2);
assert(i == 2);
i = 2;
assert((i /= 2) == 1);
assert(i == 1);
i = 3;
assert((i %= 2) == 1);
assert(i == 1);
i = 0xFF;
assert((i &= (char)0x00) == (char)0x00);
assert((char)i == (char)0x00);
/* same others bitwise, except ~= */
}
/*
# ternary operator #question mark #?
Called ternary operator since it is the only operator that
takes 3 inputs.
It seems that the only use for the ternary operator is writing less,
so it is completely redundant with and if else:
<http://stackoverflow.com/questions/758849/the-ternary-conditional-operator-in-c>
*/
{
assert((1 < 2 ? 3 : 4) == 3);
assert((1 > 2 ? 3 : 4) == 4);
/* The ternary operator can also yield lvalues. */
{
int x = 0, y = 1, *xp = &x, *yp = &y;
*(1 ? xp : yp) = 10;
assert(x == 10);
}
/* The possible to initialize consts with the ternary operator. */
{
const int i = 0 ? 1 : 2;
char *s = 0 ? "a" : "b";
}
}
/*
# comma operator
Obscure and almost useless C operator.
*/
{
/*
Commas here are part of the declarator sequence,
just like in functions calls/defs. They are not
comma operators!
*/
int i=0, a=1, b=2, c=3;
/*
ignores values on left
takes only last value on right
BAD: operations on left has no effect
*/
assert((i = 0, 1 ) == 1);
assert((i = 0, i = 1, 2) == 2);
/*
assign has precedence over comma
BAD: operation on right has no effect
*/
{
i = 2;
(i = 0), 1;
i = 0, 1;
assert(i == 0);
}
/* ERROR */
/* declaration int j does not return a value */
/*int j=0, 1;*/
/* operation on left comes first */
{
i=2;
assert((i=0, i) == 0);
i=2;
assert((i=0, i++, i) == 1);
}
/* must be parenthesis protected when passesd as function argument */
/* to differentiate from argument separtor comma */
{
int i = 0;
assert(int_func_int((i++, i)) == 1);
}
}
}
/*
# pointer
pointers contain addresses of variables instead of the value
using the dereference operator `*`, you can get the value from the address
*/
{
int i;
int *pi, *pi2;
/* BAD */
/* you are modifying some random piece of memory!!!! */
/* must declare like that: multiple stars */
/**pi = 7;*/
pi = &i;
*pi = 1;
assert(i == 1);
assert(*pi == 1);
i = 2;
assert(i == 2);
assert(*pi == 2);
printf("(void*)pi = %p\n", (void*)pi);
printf("(void*)(pi+1) = %p\n",(void*)(pi+1));
/* OK: implicit conversion * -> int: */
pi2 = pi + 1;
printf("(void*)(pi2-pi) = %p\n", (void*)(pi2-pi));
assert(pi2 - pi == 1);
/* ERROR: incompatible pointer type */
/*float* fp = &i;*/
/* OK: works with explicit cast: */
float* fp = (float*)&i;
/*
# single line multiple pointer declaration
You must put an asterisk for each pointer, or they are not taken to be pointers!
This is not very intuitive since the asterisk is part of the type, not of the variable.
*/
{
/* correct */
{
int i, *ip ;
ip = &i;
}
/* ERROR: ip2 is not a pointer, but an int! */
{
/*int i;*/
/*int* ip, ip2;*/
/*ip = &i;*/
/*ip2 = &i;*/
}
}
/*
# NULL pointer
Good source: <http://c-faq.com/null/macro.html>
Basic usage: indicate error as return value from function
*/
{
/*
Why it works: it never points to any possible valid memory location.
(`&` operator never gives anything equal to it).
this is so guaranteed that gcc emmits a warning in the following code
*/
{
int i = 0;
/* WARN GCC 4.7 warning: &i will never be null. Smart. */
/*assert(&i != NULL);*/
}
/* how it prints like: */
printf("NULL = %p\n", NULL);
/* `if(NULL)` and `if(!NULL)` in error checking code always work as expected */
assert(!NULL);
/*
# NULL macro vs 0
Relationship to 0: typecasting `(int)0` to any pointer type as
`(int*)0`, `(char*)0` always gives NULL.
This is a valid way of representing the NULL pointer,
but it is better style to always use the `NULL` macro
The exact definition of `NULL` is implementation dependant.
A very common implementation is as `(void*)0`.
C++11 also introduces the related `nullptr`.
*/
{
assert(NULL == (int*)0);
assert(NULL == (char*)0);
printf("sizeof(NULL) = %zu\n", sizeof(NULL));
}
/* ERROR: comparison of distinct pointer types requires a cast: */
{
/*assert((int*)0 == (char*)0);*/
}
/*
Never dereference the NULL pointer since it is guaranteed to point to nothing.
TODO to ANSI C, undefined behaviour? or guaranteed error?
May lead to a Segmentation fault.
*/
{
/*volatile int i = *(int*)NULL;*/
}
}
/*
# void pointer
Cannot be dereferenced without typecast.
Can be typecast implicily to/from any *data* type.
Not allowed implicitly in C++.
For function pointers:
- C leaves it undefined
- POSIX 7 allows
- C++ forbids it, C++11 allows it conditionally
*/
{
void* vp;
int* ip;
int i = 0;
typedef struct S { int i; int j; } S;
S s = {0, 1};
/*
There is no corresponding data type.
Since there is no data, there is no data size.
This means that `sizeof(void)` is not possible, nor are pointer arithmetic operations.
*/
{
/* it is however possible to get the size of a `void*` */
printf("sizeof (void*) = %zu\n", sizeof(void*));
/* ERROR: invalid application of sizeof to void type */
/*vp = vp + 1;*/
}
/* int* to void*: */
vp = (void*)&i;
/* void* to int*: */
ip = (int*)vp;
/* void* to int. GCC 4.8: cast from pointer to int of different size: */
/* `-Wpointer-to-int-cast */
/*i = (int)vp;*/
/*
Typecast to the bad type.
Compiles and runs!
*/
{
/* ERROR: aggretage value used where integer was expected */
/* i = (int)s; */
/* HAHA: you can't stop me now compiler! */
vp = (void*)&s;
ip = (int*)vp;
i = *ip;
/* Proabably defined because it is the first field. */
/* Reordering is not possible, but what about padding before first field TODO? */
/*assert(i == 0);*/
}
/*
# Applications of void*
If possible, avoid them, since they allow you to bypass type safety.
Valid use cases:
- In libc, it is the return type of `malloc`, since it cannot know what type of pointer to return.
You should use implicit casts with it only:
<http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc>
- Extra parameters to callback functions.
The callback caller cannot know beforehand how many extra parameters. Solution:
- add a `void *` argument to caller and callback. `payload` is a common argument name.
- pass a struct pointer to the caller with the extra parameters
- pass the `void *` argument to the callback on the caller body
- in the callback body typecast the void* to the struct and use it
Of course, you can typecast to a different type than passed,
and if you do so welcome to the magic land of undefined behavior.
*/
{
void_ptr_cb_payload payload = {4};
void_ptr_cb_payload2 payload2 = {4, 8};
assert(void_ptr_caller(1, void_ptr_cb , &payload ) == 7);
assert(void_ptr_caller(1, void_ptr_cb2, &payload2) == 15);
}
}
}
/*
# array
C arrays are simply lots of values put side by side on memory.
Because they are side by side, it is simple to get the nth value
quickly (random access), unless like, say, a linked list, in which
you have to go follow lots of links before you reach the searched value.
*/
{
{
int is[3];
is[0] = 0;
is[1] = 1;
is[2] = 2;
assert(is[0] == 0);
assert(is[1] == 1);
assert(is[2] == 2);
}
{
int is[] = { 0, 1, 2 };
assert(is[0] == 0);
assert(is[1] == 1);
/* Allocates exact size. */
assert(is[2] == 2);
/* ERROR */
/*is = {3,4,5};*/
}
{
int is[4] = { 1, 2 };
assert(is[0] == 1);
assert(is[1] == 2);
assert(is[2] == 0);
assert(is[3] == 0);
}
{
int is[4] = { 1, 2 };
int is2[4] = { 1, 2 };
/* ERROR incompatible pointer types */
/*is = is2;*/
}
/*WARN array too small*/
{
/*int is[2] = { 1, 3, 2 };*/
}
/* ERROR no negative sized array! */
{
/*int is[-1];*/
}
/*
ERROR no 0 size array
Possible as a gcc extension.
*/
{
/*int is[0];*/
}
#if __STDC_VERSION__ >= 199901L
/*
# Designated initializer for arrays
Allows to initialize array elements in any order.
*/
{
{
int is[] = {
[1] = 1,
[0] = 0,
};
assert(is[0] == 0);
assert(is[1] == 1);
}
/* missing elements are zeroed */
{
int is[2] = {
[1] = 1,
};
assert(is[0] == 0);
assert(is[1] == 1);
}
/*
Multiple assignments for a single int.
BAD but possible.x
Only last takes effect.
*/
{
int is[1] = {
[0] = 0,
[0] = 1,
};
assert(is[0] == 1);
}
/* arrays of structs can refer multiple times to the same struct */
{
struct S { int i; int j; };
struct S ss[] = {
[0].i = 0,
[0].j = 1,
[1].i = 2,
[1].j = 3,
};
assert(ss[0].i == 0);
assert(ss[0].j == 1);
assert(ss[1].i == 2);
assert(ss[1].j == 3);
}
/*
Mix designated and non designated initialization.
Non deignated pick off where the last designated left.
Non specified ones are zero.
*/
{
{
int is[4] = {
-1, /* [0] */
/* [1] was not specified, so it is 0. */
[2] = 1,
2, /* [3], because it comes after [2] */
};
assert(is[0] == -1);
assert(is[1] == 0);
assert(is[2] == 1);
assert(is[3] == 2);
}
/* possible to overwrite values */
{
int is[2] = {
0, /* [0] first assign */
1, /* [1] first assign */
[0] = 2, /* [0] second assign, overwrites first */
3, /* [1] because comes after [0], second assign, overwrites first */
};
assert(is[0] == 2);
assert(is[1] == 3);
}
}
}
#endif
/*
# 1[is]
Obscure and confusing access syntax that you should
never use except to surprise your friends.
All that the standard says is that: a[b] = *(a + b).
If a is the int and b the pointer or the contrary
does not matter: all that matters is that one is an int and the other a pointer.
This seems to have been left like this since it is easier to compile.
<http://stackoverflow.com/questions/381542/in-c-arrays-why-is-this-true-a5-5a>
*/
{
int is[] = { 1, 3, 2 };
assert(is[1] == 1[is]);
}
/*
# Get array length on compile time
*/
{
int is[] = {0, 1, 2};
assert(sizeof(is)/sizeof(is[0]) == 3);
}
/*
# Set array length from a variable
Before C99, array length had to be a compile time constant expression (C99 6.6):
therefore you could not use variables for it, even `const` variables
(which can be modified via typecasts).
The two workarounds were:
- enum
- macros
Sometimes you can also get away with `sizeof`, but this is limited.
C99 introduces VLA which allows that, but may introduce a performace overhead.
If the size is not a compile time constant expression, then the array
automatically becomes a VLA.
Bottomline: use enums. Macros have no scope, VLA has overhead.
*/
{
{
#if __STDC_VERSION__ < 199901L
/* ERROR: cannot be initialized */
/*
int n = 2;
int isVla[n] = { 1, 2 };
*/
#endif
}
{
/* ERROR: cannot be initialized */
/*
const int n = 2;
int isVla[n] = { 1, 2 };
*/
}
/* Enum. Seems to be the best general solution. */
{
{
enum N { N = 3 };
int is[N];
assert(sizeof(is)/sizeof(is[0]) == 3);
}
/* Expressions involving enums are also fine. */
{
enum N { N = 3 };
int is[N + 1];
assert(sizeof(is)/sizeof(is[0]) == 4);
}
}
/*
sizeof works well when you want to copy the size of an existing array
that had it size determined by the initialization.
*/
{
int is[] = {0, 1, 2};
int is2[sizeof(is)/sizeof(is[0])];
assert(sizeof(is2)/sizeof(is2[0]) == 3);
}
/*
# Macro
Shares the disadvantage of every macro of having no scope.
Use enum instead.
*/
{
#define DEFINESIZE 3
int is[DEFINESIZE];
is[2] = 1;
}
#if __STDC_VERSION__ >= 199901L
/*
# VLA
# Variable length array
Implementation:
- increase/decrease stack pointer
- requires one addition and one multiplication per declaration
Pros and cons:
<http://stackoverflow.com/questions/3082126/c99-faq-and-variable-length-arrays>
*/
{
srand(time(NULL));
int size = 1 + (rand() % 10);
int vla[size];
/* sizeof is evaluated at runtime for VLAs */
assert(sizeof(vla) == size * sizeof(int));
/*
VLAs can be passed to functions.
<http://stackoverflow.com/questions/17371645/parameter-of-a-function?lq=1>
*/
{
size_t size = 2;
int vla[size];
vla_arg(size, vla);
}
/*
If the size must come after the vla (for example, to interface witha FORTRAN
interface that does so), the only possibility is to use K&R function definition syntax!
This is one of the very few application of K&R syntax to C99.
*/
{
size_t size = 2;
int vla[size];
vla_arg_k_and_r(vla, size);
}
}
}
#endif
/* Array type madness. */
{
/* Pointers and arrays are different types. */
{
assert(sizeof(int*) != sizeof(int[3]));
assert(sizeof(int[3]) == 3 * sizeof(int));
/*
# int []
Is this a type? is it different from int*?
*/
}
/* Some operators like `+` implicly convert arrays to pointers to the same type. */
{
int is[2];
assert(sizeof(is + 1) == sizeof(int*));
}
/*
ERROR: declaration of `vs` as an array of voids.
You cannot have an array of void: how many bytes should the compiler allocate?
*/
{
/*void vs[2];*/
}
/* ERROR: ou can't declare multidimentional arrays like that. */
{
/*int[2] iss[2];*/
}
}
/* Locations in memory of an array. */
{
int is[3];
puts("locations of array:");
printf("(void*)is = %p\n",(void*)is);
printf("(void*)&is[0] = %p\n",(void*)&is[0]);
printf("(void*)&is[1] = %p\n",(void*)&is[1]);
printf("(void*)&is[2] = %p\n",(void*)&is[2]);
}
/* Loop array. The only way is with the good and old for loop. */
{
int is[] = { 0, 1, 2 };
int i;
for (i=0; i < sizeof(is)/sizeof(is[0]); i++) {
printf("%d ",is[i]);
}
}
/*
# Bounds breaking
No bound check is done to avoid overhead.
Time to break down the program by making this access memory
locations it should not try to access! =)
Other less fun languages check those things and allow programs to avoid breakdown:
C does not. You try to cheat your OS, and the OS kills you.
The C standard specifies that such actions lead to unspecified behaviour.
It may lead to Segmentation faults or not.
Note however that this does not always happen, as a program may
just access another location inside its legal memory address space
but in a completelly unpredicatable manner, and the os has no way to it did this
This leads to very hard to debug errors, but is inevitable if you want
to avoid the overhead of checking arrays bounds on every dereference
*/
{
int is[2] = { 0, 1 };
volatile int j;
size_t i;
/*
GCC 4.7 is smart enough to warn agains this one.
*/
{
/*j = is[2];*/
}
/*
GCC 4.7 is not smart enough to warn agains this one!
May lead to segmentation faults, but this is unlikely.
Unspecified behaviour.
*/
if (0) {
srand(time(NULL));
i = rand() % 2;
printf("overflow = %d\n", is[2 + i]);
}
/* This will almost certainly lead to a segmentation fault. */
if (0) {
for (size_t i = 0; i < SIZE_MAX; i++) {
is[i] = 0;
/*j = is[i];*/
}
assert(is[0] == 0);
}
}
/*
# Multidimentional arrays
Before using them, always consider using single dimentional arrays,
which are much simpler to handle with some multiplication and modulos.
It is easier to explicily calculate indexes than to deal with the C
type system.
Cases where this would be a better design choice: TODO
*/
{
int *m1[2];
int m11[] = { 1, 2, 3 };
int m12[] = { 4, 5, 6, 7 };
m1[0] = m11;
m1[1] = m12;
/* ERROR: cannot know how much memory to allocate! */
/*int m31[][3];*/
/* Error: = {...} works only at declaration */
/*int m111[2][3];*/
/*m111[0] = &(int*[3]){1,2,3};*/
/* Allocate the exact ammount: 2 pointeres to int[3]. */
int m2[][3] = {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
/* Allocate 3x3, fills only 2x3. The rest is 0 or m3[0] gets a NULL pointer? */
int m3[3][3] = {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
/*
ERROR: last must be there.
This is an array of m[3] arrays!!
the data on an array is sequentially written to RAM
and all of its elements have a fixed size (so they can be indexed!)
If you don't know the `sizeof(m[3])`, (and you don't know the sizeof(m[]!))
you can't put all those m[3] sequentially on the RAM.
The compiler could look at each element of the initialization
and ensure they all have the *same size*, and then take that size,
but this would take a long time, so it just forces the user to input this
*/
{
/*int m3[][] = {*/
/*{ 1, 2, 3 },*/
/*{ 4, 5, 6, 7 }*/
/*}*/
}
/*
Pass multidimentional arrays to functions.
Never do that: pass an array, give m and n and do some operations instead.
*/
{
puts("\npass multidim to func:");
enum { mc = 2 };
/* Two int pointers. */
int* mat[mc];
int mat1[][3] = {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
int i;
for(i = 0; i < mc; i++) {
/* First points to the int at address 0 of the matrix mat1. */
mat[i] = mat1[i];
}
print_array(mat,2,3);
}
/* Multidimentional > 2 */
{
int m4[][2][3] = {
{ { 1, 2, 3 }, { 4 , 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12} }
};
/* Allocates exact amount for first: 2x2x2. */
int m41[3][2][3] = {
{ { 1, 2, 3 }, { 4 , 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12} }
};
/* Allocates one extra for first dimension */
/* ERROR: only first can be empty: */
/*
int m4[][][2] = {
{{1,2},{3,4}},
{{5,6},{7,8}}
};
*/
enum { mc=2, nc=4 };
int m5[mc][nc];
/* ERROR: TODO why? */
/*
int m6[][nc] = {
{1,2,3},
{4,5,6}
};
*/
/*
int m7[mc][nc] = {
{1,2,3},
{4,5,6}
};
*/
}
/* Matrix pattern. */
{
int i, j;
for(i = 0; i < 2; i++) {
printf("\n");
for(j = 0; j < 3; j++) {
printf("%d ", m1[i][j]);
}
}
printf("\n\n");
}
}
/*
# string
By convention, *C strings* are simply char arrays
terminated by the null character.
This convention is used throughout libc string functions,
such as `printf`, `strcmp` and others
so that you don't have to pass an additional size parameter to them
(those functions stop operating when they see the first null char).
Nothing prevents you from making a "string" that contains a null char,
except that you will break a very well stabilished convention,
and libc functions will not work properly with it...
If you absolutelly need a "string" with a null char, just use regular
array functions to manipulate it, and pass string lengths around.
*/
{
/* Basic example. */
{
char cs[] = "abc";
/* SAME: */
/*char cs[] = { 'a', 'b', 'c', '\0' }*/
assert(cs[0] == 'a' );
assert(cs[1] == 'b' );
assert(cs[2] == 'c' );
assert(cs[3] == '\0');
cs[0] = 'A';
assert(strcmp(cs, "Abc") == 0);
/* ERROR: you cannot assign a string to memory like this, */
/* except at initialization */
/*cs = "Abc";*/
/* You probably want `strcpy`. */
}
/*
# Iterate string
*/
{
/* Pointer version. */
{
char s[] = "abc";
char s2[] = "ABC";
char* cPtr;
for (cPtr = s; *cPtr != '\0'; cPtr++){
*cPtr = toupper(*cPtr);
}
assert(strcmp(s, s2) == 0);
}
}
/* Initialize strings */
{
/*
# Text segment
C allows you to point directly to the text segment.
In short, the text segment is the part of RAM memory reserved to a process
that contains the instructions of the process, and not, say, regular variables.
Process are not allows to modify those intructions at runtime,
and therefore you cannot modify strings that point to the text segment.
Using text segment pointers has the upside of being memory efficient as you
don't copy the text from.
Note however that you cannot modify that string.
*/
{
/* To create a pointer to text segment, initialize it as: */
{
char* cs = "abc";
assert(cs[0] == 'a');
}
/* Segmentation fault: text segment cannot be modified */
{
/*cs[0] = '0';*/
}
/* TODO why can't you do the same thing with integers? ex: */
{
/*int * is = { 1, 3, 2 };*/
}
}
/*
Parenthesis. Legal but ugly. GCC 4.8 gives an error with `-pedantic`.
*/
{
/*char s[] = ("abc");*/
}
}
/*
# String literals
http://en.cppreference.com/w/c/language/string_literal
*/
{
/* Escape chars in string conts */
{
/* Octal bytes */
assert(!strcmp("\141", "a"));
/* Hexadecimal bytes */
{
assert(!strcmp("\x61", "a"));
/*
WARNING: Hex escape out of range.
Happens because f can be part of a hex literal,
and C tries to put it together.
TODO what happens exactly according to ANSI C?
Undefined behaviour?
*/
/*{ "\xfff"; }*/
/*
The solution is to either concatenate strings, or use another escape:
*/
assert(strcmp("\xff""f", "\xff\x66") == 0);
/* Chinese UTF-8. */
puts(">>>\xe4\xb8\xad<<< zhong1, chinese for \"middle\" in utf8");
}
/*
\0 is the NUL char, but you can't insert is directly on the literal,
or else the string is interpreted to end there since C strigs are NUL terminated.
*/
printf(">>>%c<<< NUL char\n", '\0');
/* Double quotes. */
assert(strcmp("\"", "\x22") == 0);
/* Single quote. Likely exists for symmetry with character literals. */
assert(strcmp("\'", "\x27") == 0);
/* Backslash. */
assert(strcmp("\\", "\x5c") == 0);
/*
WARNING: Unknown escape sequence. TODO what ANSI C says can happen?
*/
/*assert(strcmp("\c", "\x0b") == 0);*/
/* Alert. Your terminal may interpret this as a sound beep or not. */
assert(strcmp("\a", "\x07") == 0);
/* Backspace. */
assert(strcmp("\b", "\x08") == 0);
/* Feed */
assert(strcmp("\f", "\x0c") == 0);
/* New line */
assert(strcmp("\n", "\x0a") == 0);
/* Carriage return */
assert(strcmp("\r", "\x0d") == 0);
/* Tab */
assert(strcmp("\t", "\x09") == 0);
/* Vertical tab */
assert(strcmp("\v", "\x0b") == 0);
/* Famous extensions: \e GNU for ESC */
}
/* String literals may be concatenated */
/* no spaces are implied. */
{
char cs[] = "ab" "cd";
assert(strcmp(cs, "abcd") == 0);
/* This cannot be done with variables, */
/* but can be useful if you have a string that is defined in a macro: */
{
#define STRING_AB "ab"
char cs[] = STRING_AB "cd";
assert(strcmp(cs, "abcd") == 0);
}
/* Another application is to break a long string literal over severl lines */
/* no newline is implied: */
{
char cs[] = "ab"
"cd";
assert(strcmp(cs, "abcd") == 0);
}
/* It is not possible to break a string literal on multiple lines. */
/*
{
char cs[] = "ab
cd";
assert(strcmp(cs, "abcd") == 0);
}
*/
}
}
}
}
/* # Branching statements */
{
/* # if */
{
/* Only 0 counts as false. */
if (0) {
assert(0);
}
if (1){
assert(1);
}
if (-1) {
} else {
assert(0);
}
if (-1) {
} else if (0) {
assert(0);
} else {
assert(0);
}
/* Can ommit braces for single statements. */
{
{
if (0) assert(0);
if (0)
assert(0);
if (0) { assert(0); }
}
{
if (0)
assert(0);
else
assert(1);
}
/* Possible but very ugly to use only one pair of braces. */
{
if (0) {
assert(0);
} else
assert(1);
if (0)
assert(0);
else {
assert(1);
}
}
}
/* Scope */
{
int i = 0;
if (1) {
int i = 1;
assert(i == 1);
}
}
}
/*
# switch
Why does this exists (could be done with if):
- readability
- not repeating the deciding variable / expression many times
- TODO is there no compilation preformance gain via special assembly instructions?).
# case
See switch.
*/
{
int i, j;
for(i = -1; i < 6; i++) {
switch (i) {
case 0:
assert(i == 0);
/* OK new inner scope */
int j;
/* ERROR redeclaration */
/*int i = 1;*/
break;
case 1:
assert(i == 1);
/* ERROR single inner scope. */
/*int j;*/
break;
/* Same action for multiple cases. */
case 2:
case 3:
assert(i == 2 || i == 3);
break;
/* Google C++ style recommends the following style. */
case 4: {
assert(i == 4);
break;
}
case 5: {
assert(i == 5);
break;
}
default:
assert(i != 0 && i != 1);
break;
}
}
/*
- case statements are just like GOTO labels
- break is like a jump
- each case does not need a corresponding break
- and switch statements can contain any other construct like `if` or `while`
even outside of a case break pair.
The major application of this is to impress your friends
with your mastery of C obscurantism.
However there is a classic optimization trick that relies on that:
<http://en.wikipedia.org/wiki/Duff%27s_device>
# Duff's device
*/
{
int i = 0;
switch (2) {
while (i < 2) {
label_switch_in_while:
case 0:
i++;
}
case 1:
i++;
break;
case 2:
goto label_switch_in_while;
}
printf("%d\n", i);
assert(i == 3);
}
}
/*
# for vs while
In theory, whatever you can to with for you can do with while.
However x86 has a loop instruction that increments and
contional jumps in a single step.
Therefore, using a simple for is a better hinto to your
compiler to use this more efficient looping instruction.
Moral: if you when know how many loops you will do, use `for`,
otherwise use `while`.
Using for also serves as self documentation telling readers that you know
beforehand how many times the loop will execute.
*/
/* # for loop */
{
/* Basic example. */
{
int i;
int is[] = { 0, 1, 2 };
for (i = 0; i < 3; ++i) {
assert(i == is[i]);
/* OK new scope. */
int i = -1;
/* From now on, the loop's `i` is invisble. */
assert(i == -1);
}
assert(i == 3);
}
/*
Like for `if`, if there is only a single statement,
braces can be omitted.
*/
{
int i;
int is[] = { 0, 1, 2 };
for (i = 0; i < 3; ++i)
assert(i == is[i]);
/* ERROR redeclaration note different if bracketes used. */
/*int i;*/
}
/*
Multiple loop variables: one of the few "uses" of the comma operator.
Arguably though, `while` loops are more readable in that case,
like in any other case that is not a straight single integer variable increase.
TODO check. Is this really the comma operator?
*/
{
int i;
float f;
for (i = 0, f = 0.0f; i * f < 7; i++, f += 0.5) {}
assert(i == 4);
}
#if __STDC_VERSION__ >= 199901L
{
/* Putting `int i = 0` inside the `for` is only possible in C99. */
{
int is[] = {0, 1, 2};
for (int i = 0; i < 3; ++i) {
assert(i == is[i]);
/* ERROR: redeclaration. */
/*int i;*/
}
/* ERROR undeclared. */
/*assert(i == 3);*/
}
/*
This allows for a second way of initializing multiple variables
in a single for, besides the existing comma operator.
This syntax does not however allow to initialize
two variables of different types.
*/
{
int is[] = {0, 1, 2};
for (int i = 0, j = 0; j < 30; ++i, j += 10) {
assert(i == is[i]);
/* ERROR: redeclaration. */
/*int i;*/
}
}
}
#endif
/* Nested loops. */
{
/* Basic example. */
{
int n = 0;
int is[] = {0, 0, 1, 1};
int js[] = {0, 1, 0, 1};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
assert(i == is[n]);
assert(j == js[n]);
n++;
}
}
}
/*
# Break out of nested loops
http://stackoverflow.com/questions/1257744/can-i-use-break-to-exit-multiple-nested-for-loops
One of the few widely accepted uses of goto.
Languages like Java have labeled loops to avoid the goto.
*/
{
/* TODO example: find number in a two dimensional array. */
}
}
/* Different loop step. */
{
int n = 5;
int step = 2;
int is[] = {0, 1, 2, 3, 4};
int js[] = {0, 2, 4};
int js2[] = {1, 3};
int j = 0;
for (int i = 0; i < n; i += step) {
assert(js[j] == is[i]);
if (i < n - step + 1)
assert(js2[j] == is[i + 1]);
j++;
}
}
/* # Backward loops. */
{
int n = 3;
int is[] = { 0, 1, 2 };
int js[] = { 2, 1, 0 };
int j = 0;
for (int i = n - 1; i >= 0; --i) {
assert(is[i] == js[j]);
j++;
}
/*
# Backward loops with unsined loop variables
Here things get messy: <http://stackoverflow.com/questions/665745/whats-the-best-way-to-do-a-reverse-for-loop-with-an-unsigned-index>
It becomes clear why the google c++ style recommends not to use unsigned,
but how can that be avoided for example for `size_t`?
*/
{
/* Infinite loop, since `i >= 0` always holds! */
/*
{
int n = 3;
int is[] = { 0, 1, 2 };
int js[] = { 2, 1, 0 };
int j = 0;
for (unsigned int i = n - 1; i >= 0; --i) {
assert(is[i] == js[j]);
j++;
}
}
*/
/*
Two variables solution.
Downside: one more variable, one extra operation per loop.
Upside: very clear.
*/
{
unsigned int n = 3;
int is[] = { 0, 1, 2 };
for (unsigned int i_fake = n; i_fake > 0; --i_fake) {
unsigned int i = i_fake - 1;
assert(is[i] == i);
}
}
/*
Module madness solution.
Downside: mind twisting.
Upside: efficient: no extra var or operation.
*/
{
unsigned int n = 3;
int is[] = { 0, 1, 2 };
for (unsigned int i = n - 1; i < n; --i) {
assert(i == is[i]);
}
}
/*
Post increment solution.
Mnemonic: the goes to operator `-->`
Downside: only works for step of 1.
Upside: efficient: no extra var or operation.
*/
{
unsigned int n = 3;
int is[] = { 0, 1, 2 };
for (unsigned int i = n - 1; i-- > 0;) {
assert(i == is[i]);
}
}
}
}
}
/* # while */
{
{
int i = 0;
int is[] = { 0, 1, 2 };
while (i < 3) {
assert(i == is[i]);
i++;
}
assert(i == 3);
}
/* # do-while */
{
int i = 0;
int i2;
int is[] = { 0, 1, 2 };
do {
i2 = 2*i*i + 3*i + (i % 2);
assert(i == is[i]);
i++;
} while (i2 < 7);
/* Don't forget the ';'. */
/*
Application Loop must execute at least once to know if it will continue.
Without do-while, you would have to either:
- `int i2 = 2*i*i + 3*i + (i % 2);`
So you have to type this huge expression twice!
- write a function that does:
2*i*i + 3*i + (i % 2);
This function is almost useless (used only twice)
adding needless boilerplate to your code.
both of which are not very attractive alternatives.
*/
}
}
/*
# function
A function is basically a branch, but in which you have to:
- know where to jump back to after return
- pass arguments
- get back a return value
*/
{
{
func_int(1.1);
func_float(1);
}
/*
# Pass string literals to functions
The following works.
It initializes the string on stack and then passes a pointer to it.
String literals should only be passed to `const char *` arguments,
since string literals cannot be modified, possibly leading to segfaults.
Ideally, all calling functions that can receive such strings should be const.
This is not however enforced by the compiler.
*/
{
func_string_abc("abc");
func_string_const_abc("abc");
/*func_string_modify("abc");*/
}
/* Two decls on the same line. */
{
assert(decl_1() == 1);
assert(decl_2() == 2);
}
#if __STDC_VERSION__ >= 199901L
/*
Pass struct and array literals to function using C99 compound literals.
Unlike string literals, array and struct literals can be modified on the function.
*/
{
func_array((int[]){1});
func_array_modify((int[]){1});
int is[] = {1};
func_array_modify(is);
assert(is[0] == -1);
func_struct_1((struct func_struct){.i = 1});
}
#endif
/* # return */
{
/*
Functions without return values.
Typecast return value to void.
*/
{
}
/* Return value is not an lval, so one cannot get its address */
{
int *ip;
/* ERROR */
/*ip = &int_func_int(1);*/
}
/*
# return struct from function.
Behaviour defined by the standards.
Assembly implementation is not specified by ANSI C,
but common techiques used in cdecl like conventions:
- put struct into several registers
- automatically add a hidden argument to functions that return structs,
allocated data on caller and pass a pointer to the struct,
and let the callee modify that pointer to return it.
Smaple: definition
struct struct_func_struct struct_func() {
struct struct_func_struct s = { 0, 1 };
return s;
}
gets converted to:
void struct_func(struct struct_func_struct* sp) {
struct struct_func_struct s = { 0, 1 };
*sp = s;
}
And calls:
s = struct_func();
Get converted to:
struct struct_func_struct temp;
struct_func(&temp);
s = temp;
or simply:
struct_func(&s);
In C it is not possible to detect which convertion was made by the compiler.
In C++ however, constructors and destructors allow to differenciate between the two above cases,
and RVO specifies that both are valid options that the compiler may take, and that the actual
results are unpredictable.
*/
{
struct struct_func_struct s;
s = struct_func();
assert(s.i == 0);
assert(s.j == 1);
}
}
/*
# Declaration vs definition
http://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration
Declaration says some information about type, definition specifies it completely.
Every definition is also a declaration.
*/
{
/*
# extern
Variable declaration without definition.
Needs extern, or else it is a definition.
But there is one more step left: initialization.
*/
{
int i;
{
extern int i;
/* ERROR: redeclaration */
/* TODO why? In particular, why does it work if outside of a function? */
/* i = 0; */
/*
TODO why? Possible outside function.
http://stackoverflow.com/questions/17090354/why-does-initializing-of-an-extern-variable-locally-inside-a-function-give-an-er
*/
{
/*extern int i = 0;*/
}
}
}
/* Declaration and definition. */
{
int i;
/* Separate initialization. */
i = 0;
assert(i == 0);
}
/*
Variable declaration, definition and initialization in one statment.
*/
{
int i = 0;
assert(i == 0);
}
/* struct declaration */
{
}
/* Function declaration vs definitions. */
{
/* Function declaration. extern semantics by default. */
void f();
/*
# Local functions
Declaration can be done inside other functions.
Definitions not.
Functions definition inside functions exist only as extensions
in certain compilers such as gcc if ANSI is not enforced.
*/
{
/* ERROR: no definition inside another function: */
/*void func(){}*/
/* The following as defined outside main. */
decl_def();
}
/*
Function declarations don't need argment names.
If those are used for documentation purposes, they don't need to match those of the definition.
This is highly confusing however.
Definitions need parameter names.
TODO check: This rule changed in C++.
*/
{
void decl_def_no_arg_name(int, float, char c);
decl_def_no_arg_name(0, 0.0, 'a');
}
/*
Like for structs, one major application of forward declarations
is to break definition dependency loops.
*/
{
assert(factorial2funcs0(4) == 24);
assert(factorial2funcs1(4) == 24);
}
/*
In C89, some functions can be used without any declaration as long as they are defined in another file.
They are called implicit functions.
They are not allowed in C89.
But you can use functions which have a declaration that is not a prototype (i.e. without argument checking).
*/
}
/*
Declarations can be done any number of times.
Definitions only once per scope (block or static in files).
*/
{
{
extern int i;
extern int i;
struct s;
struct s;
void f();
void f();
}
{
int i;
/* ERROR: redeclaration of i */
/* TODO why is the message redeclaration instead of redefinition? */
/*int i;*/
struct s { int i; };
/* ERROR: redefinition of s */
/*struct s { int i; };*/
}
}
/* Cannot redeclare a symbols as one of another type. */
{
struct i;
/* ERROR i redeclared as nother type */
/*void i();*/
}
/*
# Identifier list
# Parameter list
TODO
- http://stackoverflow.com/questions/18820751/identifier-list-vs-parameter-type-list-in-c
*/
{
/*
# Prototype vs declaration
http://stackoverflow.com/questions/5481579/whats-the-difference-between-function-prototype-and-declaration
- Prototype is a declaration that specifies the arguments.
Only a single prototype can exist.
- a declaration can not be a prototype if it does not have any arguments.
The arguments are left unspecified.
- to specify a prototype that takes no arguments, use `f(void)`
In C++ the insanity is reduced, and every declaration is a prototype,
so `f()` is the same as `f(void)`.
Save yourself some headache, and never write declarations that are not prototypes.
TODO why would someone want to use a declaration that is not a prototype?
*/
{
/* Declaration that is not a prototype. */
void proto_decl();
/* Prototype. */
void proto_decl(int);
/* OK, same prototype as above. */
void proto_decl(int i);
/* ERROR: conflicting type for */
/*void proto_decl(float);*/
/* A definition without arguments however already implies `(void)`. */
/* ERROR */
/*int proto_empty_definition(int);*/
assert(proto_empty_definition() == 1);
/*
# float on a prototype after a declaration
You can't use `float`, `char`, etc.: only `int`, `double`
on prototypes that follow declarations!
http://stackoverflow.com/questions/5481579/whats-the-difference-between-function-prototype-and-declaration
*/
{
void proto_decl_float();
/* ERROR: An argument that has default promotion can't match*/
/*void proto_decl_float(float);*/
void proto_decl_double();
void proto_decl_double(double);
}
/*
# void argument vs no argument
http://stackoverflow.com/questions/693788/c-void-arguments
*/
{
/* Prototype that takes no arguments. */
void void_arg(void);
/* ERROR: void must be the only parameter */
/*void void_int_arg(int, void);*/
/* WARN: parameter has void type */
/*void void_arg2(void v);*/
}
}
/* But not with different return types. */
/* ERROR conflicting types for `f` */
/*int f();*/
}
}
/*
# Implicit int
# Default return type
http://stackoverflow.com/questions/12373538/warning-return-type-defaults-to-int-wreturn-type
In C89, if not specified, the return type defaulted to `int`.
Appears to have been made illegal in C99.
`gnu99` allows it by default but gerenrates warnings, `-Wno-return-type` to turn off.
*/
{
#if __STDC_VERSION__ <= 199901L
static s;
assert(default_return_type() == 1);
#endif
}
/*
# K&R function declaration
This form of funciton declaration, while standard,
is almost completely obsolete and forgotten today.
It is however still ANSI C.
There seems to be only one case in which it may allow for something
that ANSI C declarations don't: <http://locklessinc.com/articles/obscurec/>
*/
{
char c = 0;
assert(k_and_r(1, &c) == 0);
}
/*
# Function pointers
Functions can be stored in pointers and used through them.
This is spcially useful to many related lots of functions inside a single
struct to achieve a similar effect to that found on object oriented programming.
*/
{
/*
Basic usage.
Declare a function pointer named `f` that points to functions that take 2 ints
and return one int.
*/
{
int (*f)(int n, int m);
f = add_int;
assert((*f)(1, 2) == 3);
f = sub_int;
assert((*f)(1, 2) == -1);
}
assert(add_int != sub_int);
/* Function pointers can also be passed to functions of course. */
{
assert(int_func_func_int_int(add_int, 2, 1) == 3);
assert(int_func_func_int_int(sub_int, 2, 1) == 1);
}
/*
Array of function pointers.
The array indication goes after the name of the array!
*/
{
int (*fs[])(int n, int m) = {add_int, sub_int};
assert((*fs[0])(1, 2) == 3);
assert((*fs[1])(1, 2) == -1);
}
/*
There are multiple ways to initialize and use function pointers because of implicit conversions.
<http://stackoverflow.com/questions/6893285/why-do-all-these-crazy-function-pointer-definitions-all-work-what-is-really-goi>
*/
{
/* Alternative initialization methods. */
int (*fs[])(int n, int m) = {
&add_int,
add_int,
*add_int,
**********************add_int,
};
/* Alternative call methods. */
for (int i = 0; i < 4; i++) {
assert(( fs[i])(1, 2) == 3);
assert(( *fs[i])(1, 2) == 3);
assert((******fs[i])(1, 2) == 3);
/*assert((&fs[i])(1, 2) == 3);*/
}
/* ERROR no alternative for the declaration. */
{
/*int (f)(int n, int m) = add_int;*/
}
}
}
/*
# variadic function
Takes a variable number of arguments.
Used for example on `printf`.
Possible to implement efficiently because of C 's calling convention.
*/
{
assert(variadic_add(3, 1, 2, 3) == 6);
assert(variadic_add(5, 1, 2, 3, 4, 5) == 15);
char s[32];
sprintf_wrapper(s, "%c", 'a');
assert(s[0] == 'a');
/*
The only problem with the wrapper is that compile time error checking is not done.
This could be achieved via the gcc `__attribute__((format,X,Y))` extension
*/
{
/* Error checking is not done for the wrapper. */
/* Might segfault at runtime. */
if (0) {
sprintf_wrapper(s, "%s" /*missing arg*/);
printf("sprintf_wrapper wrong = %s\n", s);
}
/* WARN type error checking is done for `sprintf`. */
/*sprintf(s, "wrong %s");*/
}
}
#if __STDC_VERSION__ >= 201112L
/*
# _Noreturn
Indicates that a function never returns.
E.g.: a function that always runs:
- `exit()`
- `longjmp`
*/
{
/*noreturn_func();*/
/*noreturn_func2();*/
}
#endif
/*
# inline keyword
Signals the compiler that it may be worth to copy paste the function instead of calling it.
The compiler is not obliged
effects:
- avoids function call, thus potentially faster
- code gets larger
- function pointer comparisons may differ for the same function
- instruction cache might be come less efficient making thigs slower
Sources:
- <http://www.greenend.org.uk/rjk/tech/inline.html>
Some warnings about inline and its usage.
*/
{
assert(inline_func(0) == 1);
}
}
/*
# goto
One of the most basic loops: tranlates to an unconditional `jmp` in x86.
*/
{
/*
However, avoid using this as it may generate unreadable code.
Opinions vary, but possible acceptable uses are:
- break out of nested loops, widely supported
- any forward jump, e.g. for error handling.
Those are equivalent to return, which is well accepted.
Very few people support gotos that go backwards.
`return` is essentially a forward jump inside a function.
*/
/* Basic example. */
{
goto basic_example;
assert(0);
basic_example:
assert(1);
}
/*
goto cannot cross functions: that would lead to crazy
things like uninitialized parameters, and no return.
Use `setjmp` for that.
*/
{
int i;
goto_func_after:
i = 1;
/*goto in_func_label;*/
}
/* Labels cannot be at the end of compound statments */
{
{ /*label_end_compound:*/ }
{ label_end_compound: 1; }
}
/* Labels and loops */
{
int i;
for ( /*label_in_for:*/ i = 0; i < 2; i++)
label_after_if:
{
label_after_if2: 1;
}
}
/* Labels and switch. */
{
int a = 1;
switch (a) {
case 0:
label_case_0:
assert(a == 1);
break;
case 1:
goto label_case_0;
break;
}
}
}
/*
# setjmp.h
Jumps without scope restrictions of goto labels.
# setjmp
Saves register states, including instruction and pointer registers.
Return value:
- 0 if did not return from longjmp
- != 0 if just returned from a lonjmp
Application: error handling a la exception. Return val encodes the exception type.
# longjmp
Restores register states.
# longjmp and signals
If you longjmp from a signal handler you can recatch the signal afterwards.
*/
{
jmp_buf env_buffer;
int val;
val = setjmp(env_buffer);
printf("setjmp = %i\n", val);
if (val != 0) {
/* Returned from longjmp. */
/* Val encodes the error code. */
} else {
/* This is evaulated normally. */
assert(setjmp_func(0, env_buffer) == 1);
/* This assert is never evaluated. */
assert(setjmp_func(1, env_buffer) * 0 == 1);
}
}
}
/* # command line args */
{
printf("argv[0] = %s\n", argv[0]);
int i = 0;
if (argc > i) {
i++;
printf("argv[%d] = %s\n", i, argv[0]);
}
if (argc > i) {
i++;
printf("argv[%d] = %s\n", i, argv[0]);
}
}
/*
# environment variables
# getenv
Returns NULL if not found.
TODO: setenv in POSIX but not in ANSI C?
*/
{
printf("getenv\n");
printf(" HOME = %s\n", getenv("HOME"));
printf(" NOT_DEFINED = %s\n", getenv("USERPROFILE"));
assert(getenv("NOT_DEFINED") == NULL);
}
/*
# preprocessor
# macros
# cpp
Does simple operations before compilation:
it is a completely separate step that happens before compilation.
Not Turing complete.
Executable name: cpp. GCC for example is just a front-end to it.
*/
{
/*
# #define
You can put preprocessor directives anywhere
but putting on global scope is the more standard and simple approach
Use defines with discretion: they make it much harder to debug!
*/
{
/*
Syntax: the line must start with `#`,
but there can be spaces after it to give indentation.
*/
{
# define SPACE_AFTER_HASH 1
assert(SPACE_AFTER_HASH == 1);
}
/* Constants. */
{
#define A B
#define B 1
assert(A == 1);
}
/* Cannot redefine macros. */
{
/* # define A 1 */
/* # define A 2 */
/*assert(A == 2);*/
}
/* Undefined evaluate equal. */
{
#if NOT_DEFINED == NOT_DEFINED2
#else
assert(false);
#endif
}
/* Functions */
{
/*
Generates:
assert(1 + 1 == 2);
Not:
assert(2 == 2);
*/
{
#define SUM(x, y) x + y
assert(SUM(1, 1) == 2);
}
/*
# macro comma protection
The macro engine has to do some kind of parsing to determine that
the comma of the function (1) is not the comma of the macro (2).
What it seems to do is simply check if the comma is between pairs of:
- parenthesis
- double quotes
and if yes ignore it.
This does not however cover C++ template parameters, and `assert` + template is a common break case
<http://stackoverflow.com/questions/4496842/pass-method-with-template-arguments-to-a-macro>
Pure C also has cases in which it is necessary to use parenthesis, for exapmle when the comma operator is used.
A more complicated case in which protecting parenthesis break:
<http://stackoverflow.com/questions/9187614/how-do-i-have-a-comma-inside-braces-inside-a-macro-argument-when-parentheses-cau>
*/
{
assert(SUM(int_int_int_func(1, 1), 1) == 3);
/* ^ ^ */
/* 1 2 */
int i = 1;
assert(SUM((i++, i), 1) == 3);
/* ^ */
/* comma operator */
/* ERROR must protect the comma operator. */
/*assert(SUM(i++, i, 1) == 3);*/
#define CAT(x, y) x y
assert(strcmp(CAT("1,", "2"), "1,2") == 0);
/* ^ ^ */
/* 1 2 */
}
assert(SUM(int_int_int_func(1, 1), 1) == 3);
#if __STDC_VERSION__ >= 199901L
/* # variadic macro functions */
{
char s[4];
#define SPRINTF(string, format, ...) sprintf(string, format, __VA_ARGS__)
SPRINTF(s, "%c%c", 'a', 'b');
assert(strcmp(s, "ab") == 0);
}
#endif
}
/*
# #include
It is possible, and very confusing, to include any type of file,
not just header files.
*/
{
int i = 0;
#include "i_plus_one"
assert(i == 1);
}
}
/*
# #undef
Undo a previous define.
*/
{
#define UNDEF_TEST 1
#undef UNDEF_TEST
#ifdef UNDEF_TEST
assert(false);
#endif
}
/*
# Double hash preprocessor operator
# ##
`##` allows to concatenate two preprocessor function arguments without spaces between them.
*/
{
/* Basic. */
{
#define CAT_NO_SPACE(x, y) x ## y
int CAT_NO_SPACE(c_, d) = 1;
assert(c_d == 1);
}
/*
Preprocessor variable gotcha:
http://stackoverflow.com/questions/1489932/c-preprocessor-and-concatenation
*/
{
{
#define VAR 3
#define CAT_VAR_FAIL(x) x ## _ ## VAR
int CAT_VAR_FAIL(b) = 1;
assert(b_VAR == 1);
}
/* Solution. */
{
#define VAR 3
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define CAT_VAR(x) EVALUATOR(x, VAR)
int CAT_VAR(b) = 1;
assert(b_3 == 1);
}
}
}
/*
# ifdef
Check if preprocessor variable is defined.
# or and ifdef
http://stackoverflow.com/questions/965700/c-preprocessor-testing-definedness-of-multiple-macros
Almost the same as `#if defined()`,
except you can use `#if defined()` with `|| on a single line as:
#if defined(X) || defined(Y)
while
#ifdef(X) || ifdef(Y)
#ifdef X || Y
compiles but does not do what you expect:
TODO legal?
For `&&`, we could get away with:
#ifdef(X)
#ifdef(Y)
but there is no alternative for `||`.
# ifndef
Negation of ifdef.
# defined
Like ifdef, but more flexible
as you can use it inside `#if` with boolean operators.
*/
{
#ifdef COMMANDLINE
/* gcc -DCOMMANDLINE c.c */
puts("C");
#else
/* gcc c.c */
puts("no C");
#endif
}
/*
# #if
# #else
# #elif
The preprocessor can do certain integer arithmetic operations such as: +, -, ==, <.
*/
{
#if 1 == 0
assert(false);
#elif 1 == 1
#else
assert(false);
#endif
#define INIF 1
#if INIF + 1 == 2
#else
assert(false);
#endif
#if 16 == 0x10
#else
assert(false);
#endif
/*
Cannot compare strings directly!
http://stackoverflow.com/questions/2335888/how-to-compare-string-in-c-conditional-preprocessor-directives
Always define to integers.
*/
#define STR1 1
#define STR2 2
#define STR STR1
#if STR == STR1
#elif STR == STR2
assert(false);
#endif
}
/*
# && preprocessor
# and preprocessor
*/
#define C 1
#if defined(C) && C > 0
#else
assert(false);
#endif
/*
# #error
Print an error message to stderr and stop compilation.
Useful to enforce preprocessor conditions.
*/
{
/* # error "the error message" */
}
/*
# null directive
A `#` followed by newline is ignored.
*/
{
#
}
/*
# pragma
C99 specifies that:
# pragma X Y Z ...
- if `X != STDC`, does something implementation defined, and therefore not portable.
Examples: `#pragma once`
- else, then the statement must take a form:
# pragma STDC FP_CONTRACT on-off-switch
# pragma STDC FENV_ACCESS on-off-switch
# pragma STDC CX_LIMITED_RANGE on-off-switch
all of which are portable.
*/
/*
# Prefined preprocessor macros
# Standard preprocessor defines
Some preprocessor vars are automatically defined by certain compilers
although they are not c standards. Those are not discussed here.
List of standard defines: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
List all them on GCC:
gcc -dM -E - < /dev/null | sort
Sample output:
#define _LP64 1
#define _STDC_PREDEF_H 1
#define __ATOMIC_ACQUIRE 2
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_CONSUME 1
#define __ATOMIC_HLE_ACQUIRE 65536
#define __ATOMIC_HLE_RELEASE 131072
#define __ATOMIC_RELAXED 0
#define __ATOMIC_RELEASE 3
#define __ATOMIC_SEQ_CST 5
*/
{
/*
# STDC_VERSION__
# __STDC_VERSION__
String representing version of the c std lib. Format: yyyymm (base 10).
Some values:
- C11: 201112L
- C99: 199901L
http://sourceforge.net/p/predef/wiki/Standards/
Apperas undefined in C99
*/
{
printf("__STDC_VERSION__ = %li\n", __STDC_VERSION__);
}
/*
# __stdc__
# stdc
1 if the implementation is conforming, 0 otherwise.
TODO check: on GCC, 1 with `-std=cXX`, 0 with `-std=gnuXX`.
*/
{
printf("__STDC__ = %d\n", __STDC__);
}
/*
# __STDC__
# STDC
1 if the implementation is conforming, 0 otherwise.
TODO check: on GCC, 1 with `-std=cXX`, 0 with `-std=gnuXX`.
*/
{
printf("__STDC__ = %d\n", __STDC__);
}
/*
# __STDC_HOSTED__
# STDC
Indicate if the compilation is hosted or not.
# Hosted
# Freestanding
Concept defined in ANSI C.
Basically, a freestanding implementation does not need to provide an stdlib.
In GCC, controlled by the `-ffreestainding` option.
*/
{
printf("__STDC_HOSTED__ = %d\n", __STDC_HOSTED__);
}
/*
# __cplusplus
Defined only if using C++ compiler.
*/
#ifdef __cplusplus
printf("__cplusplus\n");
#endif
/*
# line
# #line
Set the line and optionally filename that is seen by `__FILE__` and `__LINE__`.
*/
/*#line 1*/
/*
# __FILE__
Absolute or relative path of current file.
*/
{
printf("__FILE__ = %s\n", __FILE__);
}
/*
# __LINE__
Current source code line.
Useful for debugging.
If in a `.h`, position inside the `.h` before inclusion.
*/
{
printf("__LINE__ = %d\n", __LINE__);
}
#if __STDC_VERSION__ >= 199901L
/*
# __func__
If inside a function, the name of that function.
This is not a normal macro, since the preprocessor cannot know
the current function name, because the preprocessor does not parse.
*/
{
assert(strcmp(__func__, "main") == 0);
}
#endif
printf("__DATE__ = %s\n", __DATE__);
printf("__TIME__ = %s\n", __TIME__);
#ifdef __WIN32__
/* Automatically defined by certain compilers on windows: */
/* TODO gcc specific or not? if yes move out of here. */
puts("__WIN32__");
#endif
#ifdef _LIBC
/* TODO what is this */
/* TODO gcc specific or not? if yes move out of here. */
puts("_LIBC");
#endif
#ifdef __ILP32__
/* TODO what is this */
/* TODO gcc specific or not? if yes move out of here. */
puts("__ILP32__");
#endif
#ifdef ___X32_SYSCALL_BIT
/* TODO what is this */
/* TODO gcc specific or not? if yes move out of here. */
puts("___X32_SYSCALL_BIT");
#endif
}
}
/*
# trigraphs
Absolutelly obscure feature for very old systems which do not support certain
characters or because of keyboards which don't support them easily
It is so obscure that gcc even emmits a warning if you use those!!
Is the first substitution made to source, even before the preprocessor.
They are commented out here so that compilers like
gcc won't annoy us with warnings.
*/
{
/*assert('??=' == '#');*/
/*assert('??(' == '[');*/
/* TODO literal backslash? */
/*assert('??/' == '\');*/
/*assert('??)' == ']');*/
/*assert('??'' == '^');*/
/*assert('??<' == '{');*/
/*assert('??!' == '|');*/
/*assert('??>' == '}');*/
/*assert('??-' == '~');*/
/*
TODO how to escape a trigraph on a string literal, say: `??=` ?
is it necessary to use `\x`?
*/
/*printf("??")*/
}
/*
# dynamic allocation
Allocates ammounts of memory that are only known at runtime,
not compile time.
# malloc
The main way to get new dynamic memory.
Returns a `void*` which can be used for any type.
Typecast from `void*` is implicitly done without warning.
# dynamic allocation vs VLA
Dynamic memory has the following characteristics which VLA does not:
- no scope
therefore can be allocated in functions
and returned to caller
- heap much larger than stack
So it is more flexible, at the cost of some runtime speed.
*/
{
/* basic usage */
{
size_t bytes = sizeof(int) * 2;
int* is = malloc(bytes);
if (is == NULL) {
printf("malloc failed\n");
} else {
is[0] = 1;
assert(is[0] == 1);
free(is);
}
}
/*
# free
Main way to free dynamic memory after you are done with it.
Freeing a NULL pointer does nothing:
<http://stackoverflow.com/questions/1938735/does-freeptr-where-ptr-is-null-corrupt-memory>
*/
{
free(NULL);
/*
WARN attempted to free a non heap object.
If this compiled, it could lead to segfault.
*/
{
int i;
/*free(&i);*/
}
/* freeing a pointer twice leads to a segfault */
{
int *ip = malloc(sizeof(int));
free(ip);
/* RUNTIME ERROR: segmentation fault. */
/*free(ip);*/
}
}
/*
# realloc
Change size of allocated memory with malloc.
If you already have allocated some memory, it might be faster to enlargen it
rather than to free it and reallocate.
The library may however choose to move your memory somewhere else if not enough is available
You must use a second pointer to get its value, because in case the reallocation fails,
you still need the old pointer to clear up old memory.
*/
{
size_t bytes = sizeof(int) * 2;
int* is = malloc(bytes);
if (is == NULL) {
printf("malloc failed\n");
} else {
is[1] = 1;
/* You must use a second pointer here. */
int* is2 = realloc(is, sizeof(int) * 4);
if (is2 == NULL) {
printf("realloc failed\n");
} else {
is = is2;
is[3] = 1;
/* Old values are untouched. */
assert(is[1] == 1);
assert(is[3] == 1);
}
free(is);
}
}
/*
# calloc
Like malloc but initializes allocated bytes to zero.
why calloc? <http://www.quora.com/C-programming-language/What-does-the-c-stand-for-in-calloc>
Clear seems most likely.
Takes number of elements and elemetn size separately.
*/
{
int* is = calloc(2, sizeof(int));
if (is == NULL) {
printf("calloc failed\n");
} else {
assert(is[0] == 0);
assert(is[1] == 0);
free(is);
}
}
/*
malloc multi dimensional arrays
For a 2D N x M array, there are two solutions:
- N mallocs of size M
- one malloc of size N x M
<http://stackoverflow.com/questions/1970698/c-malloc-for-two-dimensional-array>
In C++, using vectors of vectors is an easier solution.
*/
{
/* One malloc. */
{
}
}
/*
# allocate too much memory
if you try to allocate too much memory,
`malloc` may fail, or your os will eventually decide to kill your naughty program
time to try that out!
TODO0 how to pass more than INT_MAX to malloc to break it? =)
*/
{
if (0) {
size_t n = 1024 * 1024 * 1024;
int* ip = malloc(n);
if (ip == NULL) {
printf("could not allocate %zu bytes", n);
}
free(ip);
}
/*
allocate 1024 Petabytes of RAM in 1 gb chunks!!!
someday this will be possible and people will laugh at this...
generates a segfault
*/
if (0) {
const size_t GB = 1024 * 1024 * 1024;
for (int i = 0; i < GB; i++) {
int* ip = malloc(GB);
ip[0] = 0;
if (ip == NULL) {
printf("could not allocate %zu bytes", GB);
}
}
}
}
}
/*
# Standard library.
# stdlib
This section is about the stdlib, not the language itself.
Note however that it is not possible
to implement many parts of the stdlib portably just in terms of the language:
you would need extensions for that.
E.g.: IO like `printf`.
*/
{
/*
# assert.h
Defines the assert *macro*, which exits 1 and prints out the expression that caused the error.
Do not forget that `assert` is a *macro*, or this may lead to unexpected effects, such as:
- unused variable warning because asserts got removed
# NDEBUG
If defined *before assert.h* is included, asserts do nothing.
*/
{
/*assert(1 + 1 == 2);*/
}
/*
# errno.h
Used for error handling.
Defines `errno`, which can be set by user or library functions to indicate the error type.
It is commonly used in operations such as file IO.
Also define a few possible values which libc may set `errno` to:
- EDOM. Domain error. Generated for example on `sqrt(-1.0)` of `math.h`.
- EILSEQ
- ERANGE
*Many* more such errors are defined for example by POSIX.
Each error has an error message string associated to it.
To get that error message, consider using `strerror`.
To print an error message to stderr, consider using `perror`.
*/
{
errno = 0; /* no error */
errno = EDOM; /* EDOM error */
}
/*
# stdlib.h
*/
{
/*
# system
executes command in a shell and waits for it to end before continuing current program
the shell is implementation dependant
- linux: `/bin/sh`
so in the end what you write with this is not very portable
return value is also implementation dependant but is often the command exit status
or an error reserved value
*/
{
/* Linux test. */
/*int r = system("echo a | grep b");*/
/*assert(r == 1);*/
}
/*
# atoi
# atol
# atoll
Convert string to integer.
`strtol` is better as it allows error checking, so use that instead.
C99 explicitly says that errno does not need to be set.
*/
{
assert(atoi("123") == 123);
enum N { N = 256 };
char s[N];
snprintf(s, N, "%d", INT_MAX);
assert(atoi(s) == INT_MAX);
snprintf(s, N, "%d", INT_MIN);
assert(atoi(s) == INT_MIN);
#ifdef UNDEFINED_BEHAVIOUR
snprintf(s, N, "%ld", INT_MAX + 1L);
printf("INT_MAX + 1 = %s\n", s);
printf("atoi(INT_MAX + 1) = %d\n", atoi(s));
printf("atoi(123abc) = %d\n", atoi("123abc"));
#endif
/* No hex. use strtol */
/*assert(atoi("0xA") == 10);*/
}
/*
# itoa
# ltoa
Neither POSIX nor glibc?
http://stackoverflow.com/questions/190229/where-is-the-itoa-function-in-linux
The closes one gets is an internal `_itoa` in glibc.
`sprintf` is the way.
*/
/*
# strtol
*/
{
}
}
/*
# stdio.h
stream Input and Output
*/
{
/*
# stream
An stream is an abstraction over different input/output methods
such as regular files, stdin/stdout/stderr (pipes in linux), etc.
so that all of them can be treated on an uniform basis once you opened the stream.
Most functions have a form which outputs only to stdout,
and most input functions have a form which reads only from sdtin
coupled with a general form that outputs to any stream.
Unfortunatelly, sometimes there are subtle differences between those two
forms, so beawere!
# FILE
FILE is a macro that represents a stream object.
Its name is FILE of course because files are one of the main types of streams.
However, streams can represent other resources in the filesystem in general
such as Linux FIFOs or sockets.
# stream vs file descriptors
A file descriptor is a POSIX concept and thus shall not be discussed here.
*/
/*
# BUFSIZ
TODO
*/
{
printf("BUFSIZ = %ju\n", (uintmax_t)BUFSIZ);
assert(BUFSIZ >= 256);
}
/*
# EOF
EOF is a C concept.
EOF works because there are only 256 bytes you can get from an fd
so EOF is just some int outside of the possible 0-255 range, tipically -1
In Linux for example, EOF does not exist.
The only way to know if a file is over is to make a `sys_read` call
and check if you get 0 bytes.
Since `sys_read` returns the number of bytes read, if we get less than we asked for
this means that the file is over.
In case more data could become available in the future, for example on a pipe,
`sys_read` does not return immediately, and the reader sleeps until that data becomes available.
*/
/*
# stderr
The `stderr` macro is a `FILE*` that represents the standard error.
Is is always open when the program starts.
The output to stderr may not be synchronized with that of stdout,
so this message could appear anywhere relative to other things that were
printed to stdout.
*/
{
fputs("stderr\n", stderr);
}
/*
# stdout
Sames as stderr but for stdout.
Less useful than `stderr` since most IO functions have a convenience form that writes to stdout.
*/
{
fputs("stdout\n", stdout);
}
/*
# stdin
be careful!! stdin won't return EOF automatically
For a tty you can tell the user to input a EOF (ctrl d in linux, ctrl z in windows)
but as you see this is system dependent. for pipes I am yet to find how to do this,
might be automatic when process closes only.
The best way to know that a stdin ended is recognizing some specific
pattern of the input, such as a newline with fgets, or the end of a
number with scanf
Before this comes, the program just stops waiting for the stdin to
produce this, either from user keyboard input, or from the program
behind the pipe.
*/
/* # Stream output */
{
/*
# putchar
Write single char to stdout.
Basically useless subset of putc which writes to any stream,
and very slow since it may mean several stream IO operations.
*/
{
putchar('p');
putchar('u');
putchar('t');
putchar('c');
putchar('h');
putchar('a');
putchar('r');
putchar('\n');
}
/*
# putc
putchar to any stream.
Why is it not called fputc?
*/
{
putc('p', stdout);
putc('u', stdout);
putc('t', stdout);
putc('c', stdout);
putc('\n', stdout);
}
/*
# puts
Write to stdout.
Newline appended at end.
*/
{
puts("puts");
}
/*
# fputs
Write to any stream.
Unlike puts, *no* newline is automatically appended at end!
Very confusing.
*/
{
fputs("fputs\n", stdout);
}
/*
# printf
Write formated string to sdtout.
Does not automaticaly append newlines.
It is very useful to learn the format strings,
since this has become a de facto standard and is also used
for example in python format strings and bash `printf` command.
html readable documentation on the c++11 printf format strings <http://www.cplusplus.com/reference/clibrary/cstdio/printf/>
should be close to the latest C, and backwards compatible
Since the formatting behaviour is identical to that of sprintf,
sprintf tests may be used here if the output is predictable so that output can be asserted.
*/
{
char s[256];
/*
typecasts in printf
In most cases, gcc 4.8 can emmit warning for wrong types.
TODO what happens when a wrong type is passed? Typecast? Undefined?
*/
{
printf("u UINT_MAX = %u\n", UINT_MAX);
sprintf(s, "%d", UINT_MAX);
assert(strcmp(s, "-1") == 0);
}
/* char */
sprintf(s, "%c", 'a');
assert(strcmp(s, "a") == 0);
/* int */
printf("d INT_MAX = %d\n", INT_MAX);
/* long int: */
printf("d LONG_MAX = %ld\n", LONG_MAX);
/* long long (int): */
printf("lld LLONG_MAX = %lld\n", LLONG_MAX);
/* # floating point numbers */
{
/* float and double both use the the same char `f` char: */
printf("printf float = %f\n", 1.0f);
printf("printf double = %f\n", 1.0);
/* long double: */
printf("f = %Lf\n", (long double)1.0);
/* # control number of zeros after dot */
{
/* # fixed number */
{
sprintf(s, "%.2f", 1.0f);
assert(strcmp(s, "1.00") == 0);
}
/* # given by variable */
{
sprintf(s, "%.*f", 2, 1.0f);
assert(strcmp(s, "1.00") == 0);
}
}
}
/* # Control minimum number chars to output */
{
/*
Pad with spaces, right align.
Useful to output nicely formatted tables.
Ugly:
12345 1
1 1
Beautiful:
12345 1
1 1
*/
{
sprintf(s, "%6.2f", 1.0f);
assert(strcmp(s, " 1.00") == 0);
}
/*
Pad with zeros
Useful for naming files: with `0`
- "10" comes after "09" ('1' > '0')
- "10" comes before "9" ('1' < '0')!
*/
{
sprintf(s, "%06.2f", 1.0f);
assert(strcmp(s, "001.00") == 0);
}
/*
Left align with `-`
*/
{
sprintf(s, "%-6s", "abc");
assert(strcmp(s, "abc ") == 0);
/* Does not work with zeros. gcc 4.8.1 gives a warning. */
/* sprintf(s, "%-06s", "abc"); */
/* printf("%s\n", s); */
/* assert(strcmp(s, "abc ") == 0); */
}
}
/* # Scientific */
{
char s[10];
sprintf(s, "%.3e", 1.0f);
assert(strcmp(s, "1.000e+00") == 0);
}
/* # Strings */
{
char s[4];
sprintf(s, "%s", "abc");
assert(strcmp(s, "abc") == 0);
/*
still not possible to print a null char with this
substitution is done before
*/
{
char s[] = "000";
sprintf(s, "%s", "a\0b");
/* TODO why does this fail? */
/*assert(memcmp(s, "a\00", 3) == 0);*/
}
}
/* # Hexadecimal integer output (unsigned): */
{
printf("16 in hex = %x\n", 16);
/* Letter case control. */
{
printf("0xA in hex = %x\n", 0xA);
printf("0xA in hex upper case = %X\n", 0xA);
}
printf("-1 in hex = %x\n", -1);
printf("16l in hex = %lx\n", 0x16l);
}
#if __STDC_VERSION__ >= 199901L
/* Hexadecimal scientific float output. */
{
printf("0x1.Ap11 = %a\n", 0x1.Ap11);
printf("0x1.Ap11 uppercase = %A\n", 0x1.Ap11);
printf("0x10.Ap11 = %a\n", 0x10.Ap11);
}
#endif
/*
# printf Pointers
prints the hexadeciamal linear address.
%p excpects a `void*`.
*/
{
/* 2 for "0x" and one for trailling '\0'. */
char s[ PRIxPTR_WIDTH + 3 ];
/*
non null pointers are printed in a (bad?) notation starting with `0x`
Also, trailling zeroes on the number are removed,
so address 16 is represented as `0x10`
*/
{
sprintf(s, "%p", (void*)16);
assert(strcmp(s, "0x10") == 0);
}
/* NULL pointer has a special representation as `(nil)` */
{
sprintf(s, "%p", NULL);
assert(strcmp(s, "(nil)") == 0);
}
#if __STDC_VERSION__ >= 199901L
/*
# PRIxPTR
0 pad pointers.
To print pointers and line them up nicely, one must take into account that trailling zeroes are ommited.
One option is to space pad:
%10
But this produces:
0x10
0x10000000
which is still ugly.
The ideal would then be to pad with zeros as in:
0x00000010
0x10000000
The notation:
%010p
is not supported TODO0 why not?
The solution to this introduced in C99 is to use `uintptr + PRIxPTR`:
<http://stackoverflow.com/questions/1255099/whats-the-proper-use-of-printf-to-display-pointers-padded-with-0s>
There seems to be no convenient way to take into account pointer sizes except defining thingg manually:
For example, x32 uses 4 bytes, x64 8, etc.
*/
{
printf("PRIxPTR usage = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)(void*)1);
}
}
#endif
/*
# Escape percentage.
Note that `%` is printf specific,
not string literal specific,
since percentages only have special meanings on strings passed to `printf`.
*/
{
char s[2];
sprintf(s, "%%");
assert(strcmp(s, "%") == 0);
}
/* How to printf standard typedefs. */
{
/* If they have specific format strings. Just use them. */
{
printf("printf size_t = %zu\n", (size_t)1);
printf("printf intmax_t = %jd\n", (intmax_t)1);
printf("printf uintmax_t = %ju\n", (uintmax_t)1);
}
/* If there is no format string, but the type is assured to be an integer type, */
/* typecast to the largest possible integer type and use `%jd` or `%ju`. */
{
/* Supppose that the API states that `integer_t` is a signed integer type. */
/*typedef int integer_t;*/
printf("printf integer_t = %jd\n", (intmax_t)1);
}
/*
There are some cases in which there is no specific printf format,
but there is a macro that expands to part of a format string that allows to print it correctly.
*/
{
#if __STDC_VERSION__ >= 199901L
printf("printf PRIxPTR uintptr_t = %" PRIxPTR "\n", (uintptr_t)16);
printf("printf PRIdPTR uintptr_t = %" PRIdPTR "\n", (uintptr_t)16);
/*
sprintf has a different macro defined for it!
*/
{
char s[256];
sprintf(s, "%" SCNxPTR, (uintptr_t)1);
printf("sprintf uintptr_t = %s\n", s);
}
#endif
}
/*
If a typedef is not guaranteed to be either an integer type or a floating point type,
such as `clock_t`, there seems to be no decent solution as of C99
http://stackoverflow.com/questions/1083142/whats-the-correct-way-to-use-printf-to-print-a-clock-t/17190680#17190680
The best solution is to just cast it to the largest floating point type possible
Unfortunatelly, as of c11 there is no way to get the largets floating point type
as can be done for integers:
http://stackoverflow.com/questions/17189423/how-to-get-the-largest-precision-floating-point-data-type-of-implemenation-and-i/17189562
*/
{
printf("printf clock_t = %Lf\n", (long double)(clock_t)1);
printf("printf time_t = %Lf\n", (long double)(clock_t)1);
}
}
/* Return value: number of bytes written, negative if error. */
/* for string versions, excludes traling '\0'. */
assert(sprintf(s, "%c", 'a') == 1);
}
/*
# fprintf
Same as printf, but to an arbitrary stream
*/
{
assert(fprintf(stdout, "fprintf = %d\n", 1) == 12);
}
/*
large strings to stdout
stdout it line buffered
if you fill up the buffer without any newlines
it will just print
buffer size cannot be accessed programatically
TODO0 what is the bin buffer size?
in practice, 1024 works just fine
it may be much larger than BUFSIZ
*/
{
const int bufsiz = 100000;
char buf[bufsiz];
memset(buf, 'z', bufsiz);
buf[bufsiz] = '\0';
buf[bufsiz/2] = '\n';
/* large amount of 'z's verywhere! */
/*printf("%s\n", buf);*/
}
}
/* # stream input */
{
/*
# getchar
getchar == getc(stdin)
# getc
get single char from given stream (should be called fgetc...)
it blocks until any char made available.
whatever char entered including on a tty is made available immediatelly.
*/
if (0) {
/*
echo a | c.out
a
sleep 3 | c.out
EOF after 3 secs
*/
fputs("enter a char (on linux, ctrl+d EOF): ", stderr);
/* BAD does not work. */
/*fputc('a', stdin);*/
char c = getchar();
if (c != EOF) {
fprintf(stderr, "you entered:\n%c|<<<\n", c);
}
else {
fprintf(stderr, "EOF\n");
}
}
#if __STDC_VERSION__ < 201112L
/*
# gets
Deprecated, removed in C11.
dangerous:
no size checking possible
if too much input, just seg faults
*/
if (0) {
/*printf("enter a string terminated by newline: (max %d chars, newline will be included in the string)\n", sn);*/
/*gets(s);*/
/*printf("you entered:\n%s\n\n",s);*/
}
#endif
/*
# fgets
reads up to whichever comes first:
- a newline char
- buff_size - 1 chars have been read
- the end of file was reached
if the input comes from stdin on a tty
and if user inputs more than the buffer size, this will wait until the user enters
<enter>, and only at that point will those bytes be made available for `fgets`,
the exceding chars remaining in the buffer if you try to read again.
saves result in buff, '\0' terminated
this is the safest method io method to get a line at time,
since it allows the programmer to deal with very long lines.
the trailling newline is included in the input.
*/
if (0) {
FILE* fp = stdin;
const int buff_size = 4;
char buff[buff_size];
fprintf(stderr, "enter a string and press enter (max %d bytes):\n", buff_size - 1);
if (fgets(buff, buff_size, fp) == NULL) {
if (feof(fp)) { fprintf(stderr, "fgets was already at the end of the stream and read nothing");
} else if (ferror(fp)) {
fprintf(stderr, "fgets error reading from stream");
}
}
/* Some bytes are left in the buffer, may want to reread it. */
else if (!feof(fp)) {
/* TODO why does this not work with stdin from a tty nor pipe? */
/* Why is EOF not reached even if user inputs 1 single char? */
/*fprintf(stderr, "you entered more than the maximum number of bytes\n");*/
}
fprintf(stderr, "you entered:\n%s", buff);
}
/*
# scanf
complicated behaviour
input is space separated regardless of scanf string
hard to do error checking
stops reading at newline
use only if error checking is not a priority
to do proper error checking, try `fgets` and the `strtol` family
*/
if (0) {
int i, j;
unsigned int ui;
float f;
printf("enter an integer in decimal and <enter> (max 32 bits signed):\n");
i = scanf("%d", &i);
printf("you entered: %d\n", i);
/* stuff is space separated */
/* try 123 456 789 at once. 456 789 stay in the buffer, and are eaten by the second scanf */
printf("enter an integer, a space, an integer and a <enter> (max 32 bits signed):\n");
i = scanf("%d %d", &i, &j);
printf("you entered: %d %d\n", i, j);
printf("enter a float and a newline:\n");
i = scanf("%f", &f);
printf("you entered: %.2f\n", f);
printf("enter an integer in hexadecimal and a <enter>: (max 32 bits signed)\n");
i = scanf("%x", &ui);
printf("you entered (in decimal): %d\n", i);
}
/*
# fscanf
complicated like scanf
*/
if (0) {
FILE* fp = stdin;
int i;
float f;
puts("enter a int a space and a float (scientific notation) and then EOF (ctrl-d in linux):");
if (fscanf(stdin, "%d %e\n", &i, &f) != 2) {
if (feof(fp)) {
fprintf(stderr, "fscanf reached the of file and read nothing\n");
} else if (ferror(fp)) {
fprintf(stderr, "fscanf error reading from stream\n");
}
}
fprintf(stderr, "you entered: %d %.2e\n", i, f);
}
}
/*
# File streams
# File IO
To get streams that deal with files, use `fopen`.
To close those streams after usage, use `fclose`.
# fopen
Open file for read/write
Don't forget to fclose after using! open streams are a process resource.
Modes:
- `r`: read. compatible with a,w
- `w`: read and write. destroy if exists, create if not.
- `a`: append. write to the end. creates if does not exist.
- `+`: can do both input and output. msut use flush or fseek
- `x`: don't destroy if exist (c11, not c++!)
- `b`: binary.
Means nothing in POSIX systems.
On our dear DOS/Windows and Mac OS X, automatically converts between \n and \n\r or \r.
http://stackoverflow.com/questions/229924/difference-between-files-writen-in-binary-and-text-mode
Windows also does trailing \z magic for ultra backwards compatibility.
Therefore for portability, always use this when you are going to do IO
with binary IO functions such as fwrite.
In case of error:
- return `NULL` and set `errno`.
# Text IO vs # Binary IO
# Text vs binary for numerical types
Example: an int 123 can be written to a file in two ways:
- text: three bytes containing the ascii values of `1`, `2` and then `3`
- binary: as the internal int representation of the c value, that is 4 bytes, with `123` in binary and zeroes at the front.
Advantages of text:
- it is human readable since it contains only ASCII or UTF values
- for small values it may be more efficient (123 is 3 bytes in ascii instead of 4 in binary)
- it is portable across multiple systems, while binary varies, especially byte ordering.
Advantages of binary:
- it much shorter for large integers
- inevitable for data that cannot be interpretred as text (images, executables)
# Newline vs carriage return newline
Newline carriage return realated TODO confirm
For portability, use it consistently.
In linux the difference between text methods and binary methods is only conceptual:
some methods output human readable text (`fprintf`) and can be classified as text,
while others output binary, no difference is made at file opening time
# fclose
Don't forget to close because:
- open `FILE*` are a program resource
- close also flushes
In case of error:
- return `EOF`
- set `errno`
*/
{
int elems_write[] = {1, 2, 3};
enum constexpr {nelems = sizeof(elems_write) / sizeof(elems_write[0])};
int elems_read[nelems];
FILE* fp;
char path[] = "fwrite.tmp";
/*
# fwrite
Returns number of elements written.
If less elements are written than required an error ocurred.
Why take both bytes per item and items instead of just total bytes:
http://stackoverflow.com/questions/295994/what-is-the-rationale-for-fread-fwrite-taking-size-and-count-as-arguments
It seems that no less than size per item can be writen, so we are guaranteed
that some object will not be half writen.
The byte order is implementation defined.
This is therefore not a valid way to serialize data across machines.
*/
{
fp = fopen(path, "wb");
if (fp == NULL) {
io_error("fopen", path);
}
else {
if (fwrite(elems_write, sizeof(elems_write[0]), nelems, fp) < nelems) {
io_error("fwrite", path);
}
if (fclose(fp) == EOF) {
io_error("fclose", path);
}
}
}
/*
# fread
Returns number of *elements* written, not bytes.
If less elements are returned than required then either:
- an error ocured
- the end of file was reached.
It is only possible to distinguish between those cases by using
the `feof` and `ferror` functions.
# ferror
# feof
*/
{
fp = fopen(path, "rb");
if (fp == NULL) {
io_error("fopen", path);
}
else {
if (fread(elems_read, sizeof(elems_read[0]), nelems, fp) < nelems && ferror(fp)) {
io_error("fread", path);
}
}
if (fclose(fp) == EOF) {
io_error("fclose", path);
}
}
assert(memcmp(elems_read, elems_write, nelems) == 0);
/*
# Endianess
# Byte order
The C standard does not specify how bytes are ordered in memory.
http://www.ibm.com/developerworks/aix/library/au-endianc/
*/
{
/*
Check endianess.
Works because `short int` is guaranteed to be at least of size 2.
We must work with pointers, because doing `(char)i` directly is specified ot be 1.
The compilers produces the assembly code required to do so taking endianess into consideration.
*/
{
const short int i = 1;
if ((*(char*)&i) == 0) {
printf("Endianess = big\n");
} else {
printf("Endianess = small\n");
}
}
}
}
/*
# freopen
Open a given `FILE*` again but as a different file.
*/
{
/* This will discard stdin on Linux. */
/*freopen("/dev/null", "r", stdin);*/
}
/* # Reposition read write */
{
/*
For new code, always use `fgetpos` and `fsetpos` unless you absolutely
need `SEEK_END` because ftell and fseek
must return `long` which may limit the maximum file to be read,
while `fgetpos` uses a typedef `fpos_t`
# ftell
Get current position of `FILE*`.
# fseek
Set current position in `FILE*` relative to:
- SEEK_SET: relative to beginning of file
- SEEK_CUR: relative to current position
- SEEK_END: relative to end of file
It seems that seeking after the eof is undefined behaviour in ANSI C:
<http://bytes.com/topic/c/answers/219508-fseek-past-eof>
This contrasts with POSIX lseek + write, in which the unwriten gap is 0.
*/
{
/*
long int curpos = ftell(pf);
if (curpos == -1L){
ERROR
}
*/
/*
FILE* fp;
if (fseek (fp, 0 , SEEK_SET) != 0) {
ERROR;
}
*/
}
/*
# rewind
Same as therefore useless.
fseek(stream, 0L, SEEK_SET)
*/
/*
Like ftell/fseek except that:
- the return is a typedef `fpos_t`, so it may represent larger files.
- there is a single possible reference position equivalent to `SEEK_SET`.
This makes sence since that argument was only useful for convenience.
Always use it instead of ftell/fseek.
# fgetpos
Get a position in stream that is later usable with a later call to `fsetpos`.
# fsetpos
Set position to a point retreived via fgetpos.
*/
{
}
}
/*
# flush(fp)
For output streams only.
Makes sure all the data is put on the stream.
May be necessary as the data may be in a buffer.
*/
{
/*
if (flush(fp) == EOF) {
ERROR
}
*/
/* debugging application: your program segfaults
To find where, you put printf everywhere.
However nothing shows on screen.
Solution: flush immediatelly after the printf and add a newline at the end of the printed string.
This should ensure that your string gets printed.
*/
}
/* # applications */
{
{
char path[] = "str_file.tmp";
char input[] = "asdf\nqwer";
/* Write entire string to file at once. */
{
if (file_write(path, input) == -1) {
io_error("file_write", path);
}
}
/* Read entire file at once to a string. */
{
char *output = file_read(path);
if (output == NULL) {
io_error("file_read", path);
}
assert(strcmp(input, output) == 0);
free(output);
}
/* Get file size: */
{
long size = file_size(path);
if (size == -1) {
io_error("file_size", path);
}
assert(size == strlen(input));
}
}
/*
Process a file #linewise.
Allows one to read files larger than RAM, suppposing that each line is smaller than RAM.
glibc and C++ stdlib offer the `getline` function which does it.
There does not seem to be such a function in C! <http://stackoverflow.com/questions/3501338/c-read-file-line-by-line>
*/
{
FILE* fp;
/* Maximum accepted line length is buf_size including the newline. */
enum Constexpr {buffer_size = 4};
char buffer[buffer_size];
size_t last_newline_pos, current_pos;
int linenum = 0;
long file_size;
long nbytes_read;
char path[] = "cat.tmp";
char file_data[] = "abc\nde\nfgh";
size_t file_data_size = strlen(file_data);
char lines[3][4] = {"abc\n", "de\n", "fgh\n"};
size_t current_line;
/* Prepare test. */
fp = fopen(path, "wb");
if (fp == NULL) {
io_error("fopen", path);
} else {
if (fwrite(file_data, 1, file_data_size, fp) < file_data_size) {
io_error("fwrite", path);
}
if (fclose(fp) == EOF) {
io_error("fclose", path);
}
}
/* The actual cat. */
/*
fp = fopen(path, "rb");
if (fp == NULL) {
io_error("fopen", path);
} else {
nbytes_read = buffer_size;
last_newline_pos = buffer_size;
current_line = 0;
while (fread(buffer, 1, nbytes_read, fp) == nbytes_read) {
while (current_pos != last_newline_pos)
if (buffer[current_pos] == '\n') {
assert(memcmp(&buffer[current_pos], lines[current_line], ));
last_newline_pos = current_pos;
cur_line++;
}
current_pos = (current_pos + 1) % buffer_size;
}
}
if (feof(fp)) {
io_error("fread", path);
}
if (fclose(fp) == EOF) {
io_error("fclose", path);
}
}
*/
}
/* Simple write arrays to file */
{
FILE* fp;
char path[16];
int arri[] = { 0, 1, -1, 12873453 };
float arrf[] = { 1.1f, 1.001f, -1.1f, 1.23456e2 };
strcpy(path, "arri.tmp");
write_int_arr_file(path, arri, 4);
strcpy(path, "arrf.tmp");
write_float_arr_file(path, arrf, 4, 2);
}
}
/*
# file operations
A few file operations are available in ANSI C.
They are present in <stdio.h> mainly to support file IO.
# remove #delete file
Remove a file.
int remove(const char *filename);
ANSI C does not way what happen if it does not exist.
If the file is open, the behaviour is undefined.
# rename
Rename a file.
int rename(const char *old, const char *new);
If the new file exists, undefined behaviour.
# directory operations #path
There seems to be no directory of path operations with system independent separator,
only with POSIX or Boost.
*/
/*
# perror
Print description of errno to stderr with given prefix appended, `NULL` for no prefix.
Basic way to print error messages after error on a posix function
*/
{
errno = EDOM;
perror("perror test EDOM");
}
}
/* # time.h */
{
/*
# time()
A representation of absolute time.
Returns a time_t type.
The interpretation of the return is implementation defined,
and therefore cannot be relied directly upon.
Traditionally, implementations use the number of seconds since 1970.
# time_t
All that is required is that `time_t` be an arithmetic type, either integer or floating point.
See printf for a discussion of how to print time_t.
*/
{
time_t t = time(NULL);
}
/* # CLOCKS_PER_SEC */
printf("CLOCKS_PER_SEC = %ld\n", CLOCKS_PER_SEC);
/*
# clock()
Program virtual time in number of processor clock clicks
Precision is quite limited, and if too few clicks pass, it may return 0.
# clock_t
Type returned by `clock()`.
Like `time_t`, all that is required is that `time_t` be an arithmetic type,
either integer or floating point.
See printf for a discussion of how to print a `clock_t`.
*/
if (0) {
clock_t t;
int i = 0;
t = clock();
/*
Busy waiting.
WARN: optimizer may simply skip your useless test operations
and very little time will have passed.
*/
int j = 0;
for (int i = 0; i < CLOCKS_PER_SEC * 10; i++) { j++; }
t = clock() - t;
printf("clicks = %Lf\n", (long double)t);
printf("seconds = %f\n", ((float)t) / CLOCKS_PER_SEC);
}
/*
# strftime
Convert time to a formatted string.
*/
{
}
}
/*
# string.h
String and array operations.
The `str` prefixed functions use '\0' to see ther string ends
so callers don't need to give lengths.
Many of the functions exist both on `str` and `mem` forms,
where the `mem` form also takes a size.
*/
{
/*
# memcpy
Copy one array into another.
Potentially faster than a for loop like:
for(i=0; i<3; i++){
is2[i] = is[i];
}
Since in some architectures this can be implemented with more efficient instructions
than a naive for, and your compiler may not be smart enough to optimize this if you use a for.
If overlap, undefined behavior. Use memmove in that case.
*/
{
{
int is[] = { 0, 1, 2 };
int is2[sizeof(is)/sizeof(is[0])];
memcpy(is2, is, sizeof(is));
assert(memcmp(is, is2, sizeof(is)) == 0);
}
#if __STDC_VERSION__ >= 199901L
/* Compound literal copy. */
{
int is[3];
memcpy(&is, &(int []){ 0, 1, 2 }, sizeof(is));
assert(memcmp(is, &(int []){ 0, 1, 2 }, sizeof(is)) == 0);
}
#endif
}
/*
# memmove
Same as memcpy, but overlap may happen, thus slower.
*/
{
int is[] = { 0, 1, 2, 3, 4, 5 };
int is2[] = { 0, 1, 0, 1, 2, 5 };
memmove(is + 2, is, 3 * sizeof(int));
assert(memcmp(is, is2, sizeof(is)) == 0);
}
/*
# strcpy
Copy one string (up to first '\0') into another location.
If they overlap, undefined behaviour.
Could be more efficient than a for loop since it could
tell the compiler to use a better specialized instruction.
*/
{
char cs[] = "abc";
char cs2[4];
char cs3[1];
strcpy(cs2, cs);
strcpy(cs2, "abc");
/* BAD: no born checking as always */
/*strcpy(cs3, "abc");*/
}
/*
# sprintf
Same as printf, but stores result in a given string.
Make sure that the string is large enough to contain the output.
If this is a hard and important task, consider `snprintf` + malloc.
*/
{
char cs[] = "123";
char cs2[4];
sprintf(cs2, "%s", cs);
assert(strcmp(cs, cs2) == 0);
}
#if __STDC_VERSION__ >= 199901L
/*
# snprintf
Like `sprintf`, but writes at most n bytes, so it is safer,
because it may not be possible or easy to calculate the resulting
size of a formated string.
The size given *includes* the null terminator.
*/
{
char cs[] = "123";
char cs2[3];
snprintf(cs2, 3, "%s", cs);
assert(strcmp(cs2, "12") == 0);
}
#endif
/*
# strlen
Get string length (up to first '\0').
*/
{
char cs[] = "abc";
assert(strlen(cs) == 3);
}
/*
# strncpy
strcpy with maximum chars to copy.
*/
/*
# memcmp
Compare arrays like strcmp.
# memcmp vs for loop
# strcmp vs for loop
memcmp may be is faster than for loop because
the compiler may optimize it better.
On x86, the naive optimization is:
repe cmpsb
but on GCC 4.8 for example it still uses the glibc as it is even faster!
TODO how?
One catch: float NaN.
*/
{
int is[] = { 0, 1, 2 };
int is2[] = { 0, 1, 2 };
/* Compares addresses, not data! */
assert(is != is2);
assert(memcmp(is, is2, 3 * sizeof(int)) == 0);
is[1] = 0;
assert(memcmp(is, is2, 3 * sizeof(int)) < 0);
is[1] = 2;
assert(memcmp(is, is2, 3 * sizeof(int)) > 0);
#if __STDC_VERSION__ >= 199901L
/* memcmp with compound literals. */
{
int is[] = { 2, 0, 1 };
assert(memcmp(is, &(int [3]){ 2, 0, 1 }, 3 * sizeof(int)) == 0);
}
#endif
}
/*
# strcmp
Compare two strings
*/
{
char cs[] = "abc";
char cs2[] = "abc";
assert(strcmp(cs, cs2) == 0);
/* Equality. */
assert(strcmp(cs, "abc") == 0);
cs[1] = 'a';
/* Smaller. */
assert(strcmp(cs, cs2) < 0);
cs[1] = 'd';
/* Larger. */
assert(strcmp(cs, cs2) > 0);
}
/*
# strcat
Concatenate two strings.
*/
{
char s1[5];
strcpy(s1, "ab");
char s2[] = "cd";
strcat(s1, s2);
assert(strcmp(s1, "abcd") == 0);
assert(strcmp(s2, "cd" ) == 0);
}
/*
# memchr
mem version of strchr.
*/
/*
# strchr
Search for char in string.
Return pointer to that char if found.
Return NULL if not found.
*/
{
{
char cs[] = "abcb";
assert(strchr(cs, 'b') == cs + 1);
assert(strchr(cs, 'd') == NULL);
}
/*
Find all occurences of c in cs:
there is no direct libc function for this.
*/
{
char cs[] = "abcb";
char* cp;
char c = 'b';
int is[] = { 1, 3 };
int i = 0;
cp = strchr(cs, c);
while(cp != NULL) {
assert(cp - cs == is[i]);
cp = strchr(cp + 1, c);
++i;
}
}
}
/*
# strrchr
Find last match of character in string.
*/
{
char cs[] = "abcb";
assert(strrchr(cs, 'b') == cs + 3);
assert(strrchr(cs, 'd') == NULL);
}
/*
# strstr
Find first match of string in string.
glibc has `strcasestr` which ignores the case.
*/
{
char cs[] = "abcabcd";
assert(strstr(cs, "bc") == cs + 1);
assert(strstr(cs, "bd") == NULL);
}
/*
# split
See strtok
# strtok
Split string at a given character sequence.
<http://en.cppreference.com/w/c/string/byte/strtok>
*/
/*
# strerror
Returns a readonly pointer to the description of the error with the given number:
char *strerror(int errnum);
Also consider perror if you want to print those error messages to stderr.
*/
{
printf("strerror(EDOM) = \"%s\"\n", strerror(EDOM));
}
/*
# strcoll
*/
{
/* TODO example */
}
/*
# strcspn
How many characters in s1 are there before the first character present in s2.
*/
{
assert(strcspn("ab01", "10") == 2);
assert(strcspn("a0b1", "10") == 1);
}
/*
# strpbrk
Point to the first character in s1 that is in s2.
*/
{
char *s1 = "ab01";
assert(strpbrk(s1, "10") - s1 == 2);
}
/*
# memset
Set memory block to a single value.
Like memcpy, potentially more efficient than a for loop.
*/
{
char cs[] = "abcdef";
memset(cs + 2, '0', 3);
assert(strcmp(cs, "ab000f") == 0);
}
}
/*
# ctype.h
Character classficiation functions.
*/
{
/* # isspace */
{
assert(isspace(' '));
assert(isspace('\n'));
assert(!isspace('a'));
}
/* # isdigit */
{
assert(isdigit('0'));
assert(!isdigit('a'));
}
/* # ispunct */
{
assert(ispunct('"'));
assert(ispunct('('));
assert(ispunct('.'));
assert(!ispunct('a'));
assert(!ispunct('0'));
}
/*
# toupper
# tolower
Work on characters.
There is no built-in string version:
http://stackoverflow.com/questions/2661766/c-convert-a-mixed-case-string-to-all-lower-case
*/
{
assert(tolower('A') == 'a');
assert(toupper('a') == 'A');
}
}
/*
# unicode
Use wchar.
# wchar
*/
{
#include <wchar.h>
char cs[] = "汉语";
printf("%s\n", cs);
/* BAD: only changes first byte you get trash all over: */
/*cs[0] = 'a';*/
/*printf("%s\n",cs);*/
/* WARN */
/*cs[0] = '英';*/
/* You *need* setlocale to print correctly: */
setlocale(LC_CTYPE, "");
wchar_t wcs[] = L"汉语";
printf("%ls\n", wcs);
wcs[0] = L'';
printf("%ls\n", wcs);
wcs[0] = L'a';
printf("%ls\n", wcs);
/* ERROR: non wide init */
/*wchar_t wideString2[] = "asdf";*/
}
/*
# math.h
Mathematical functions.
C99 made many improvements to it. It seems that the C community is trying to replace FORTRAN by C
for numerical computations, which would be a blessing as it would mean that the system programming
croud (C) would be closer to the numerical programming one (FORTRAN).
# redundant mathematical functions
Many functions are redundant, but are furnished because of possible speedups and better precision.
For exapmle, `sqrt` and `pow` are redundant since in theoryin theory `sqrt(x) == pow(x,0.5)`.
However, many hardware platforms such as x86 implement a `sqrt` as a single instruction,
if you use `sqrt` it will be simpler for the compiler to use the x86 sqrt instruction
if it is available.
Using the hardware instruction may be faster.
It will also possibly be more precise since it is likelly that sqrt
would need several floating point operations to implement, each one meaning a loss of precision,
while the hardware can do them a single operation.
I guess however that good compilers will optimize `pow(x, 0.5)` to `sqrt(x)`.
Anyways, it is better to play on the safe side, and always use the most specific operation possible.
# errors
The following errors exist:
# domain error
Value outside of function domain. Ex: `sqrt(-1.0)`.
Return value: implementation defined.
In other words, undefined behaviour to ANSI C, so never rely on it.
Detection: if `math_errhandling & MATH_ERRNO != 0`, `errno = ERANGE`
and a "divide-by-zero" floating point exception is raised.
# pole error
Function has a pole at a point. Ex: `log(0.0)`, `tgamma(-1.0)`.
Return value: HUGE_VAL.
Detection if `math_errhandling & MATH_ERRNO != 0`, `errno = ERANGE`
and a "divide-by-zero" floating point exception is raised.
# range errors
Occur if the result is too large or too small to fint into the return type.
There are two types of range errors overflow and underflow.
In both cases, if `math_errhandling & MATH_ERRNO != 0`,
`errno = ERANGE` and a "divide-by-zero" floating point exception is raised.
# overflow
For exapmle, around poles, functions can have arbitrarily large values,
so it is possible that for a given input close enough to the pole that the output is too large to reprent.
Return value: HUGE_VAL, HUGE_VALF, or HUGE_VALL, acording to function's return type.
# underflow
The output is too small to represent
Return value: an implementation-defined value whose magnitude is no greater than the smallest
normalized positive number in the specified type;
*/
{
const double err = 10e-6;
printf("math_errhandling & MATH_ERRNO = %d\n", math_errhandling & MATH_ERRNO);
/* # abs */
{
/* Absolute values, integer version: */
assert(abs(-1.1) == 1);
/* Absolute values, float version: */
assert(fabsl(-1.1) == 1.1);
}
/*
Max and min for floats (C99):
Don't forget to use the float versions which starts with f when you want floating operations!
*/
{
assert(fminl(0.1, 0.2) == 0.1);
assert(fmaxl(0.1, 0.2) == 0.2);
}
/*
# rounding
Many more: rint, lrint.
*/
{
assert(fabs(floor(0.5) - 0.0 ) < err);
assert(fabs(ceil(0.5) - 1.0 ) < err);
/*
# trunc
Never raises any errors because the new result always fits in the data type (magnitide decresases).
*/
{
assert(fabs(trunc(1.5) - 1.0) < err);
assert(fabs(trunc(-1.5) - -1.0) < err);
}
/*
# round
Away from 0 on mid case.
*/
{
assert(fabs(round( 1.25) - 1.0) < err);
assert(fabs(round( 1.5 ) - 2.0) < err);
assert(fabs(round( 1.75) - 2.0) < err);
assert(fabs(round(-1.5 ) - -2.0) < err);
}
/*
# modf
Decompose into fraction and integer parts.
*/
{
double d;
assert(fabs(modf(3.25, &d) - 0.25) < err);
assert(fabs(d - 3.00) < err);
}
}
/*
# fma
Fused multiple add or floating point multiply and add.
Does addition and multiplication on one operation,
with a single rounding, reduncing rounding errors.
Has hardware implementations on certain platforms.
*/
{
assert(fabs(fma(2.0, 3.0, 4.0) - (2.0 * 3.0 + 4.0)) < err);
}
/* # exponential functions */
{
/* # exp */
{
assert(fabs(exp(1.0) - 2.71) < 0.01);
}
/*
# ln
See log.
# log
Calculates the ln.
*/
{
assert(fabs(log(exp(1.0)) - 1.0) < err);
assert(fabs(log2(8.0) - 3.0) < err);
assert(fabs(log10(100.0) - 2.0) < err);
}
/*
# sqrt
Range is positive or zero. Negatives are a range error.
To get complex on negative values, use `csqrt`.
*/
{
assert(fabs(sqrt(4.0) - 2.0) < err);
/* GCC 4.7 -O3 is smart enough to see that this is bad: */
{
float f = -4.0;
/*printf("sqrt(-4.0) = %f\n", sqrt(f));*/
}
{
float f;
volatile float g;
f = -4.0;
errno = 0;
g = sqrt(f);
if (math_errhandling & MATH_ERRNO)
assert(errno == EDOM);
printf("sqrt(-4.0) = %f\n", f);
}
}
#if __STDC_VERSION__ >= 199901L
/*
# hypot
Hypotenuse: sqrt(x^2 + y^2)
*/
{
assert(fabs(hypot(3.0, 4.0) - 5.0) < err);
}
#endif
#if __STDC_VERSION__ >= 199901L
/*
# cbrt
CuBe RooT
*/
{
assert(fabs(cbrt(8.0 ) - 2.0) < err);
assert(fabs(cbrt(-8.0) - -2.0) < err);
}
#endif
/* # pow */
{
assert(fabs(pow(2.0, 3.0) - 8.0 ) < err);
}
}
/* # trig */
{
float f = sin(0.2);
assert(fabs(sin(0.0) - 0.0) < err);
assert(fabs(cos(0.0) - 1.0) < err);
/*
# PI
There is no predefined macro for PI. TODO0 why not? so convenient...
This is a standard way to get PI.
The only problem is a possible slight calculation overhead.
But don't worry much about it. For example in gcc 4.7, even with `gcc -O0` trigonometric functions
are calculated at compile time and stored in the program text.
*/
{
assert(fabs(acos(-1.0) - 3.14) < 0.01);
}
}
/* # erf: TODO0 understand */
/*
# factorial
There seems to be no integer factorial function,
but `gamma(n+1)` coincides with the factorials of `n` on the positive integers,
and may be faster to compute via analytic approximations that can be done to gamma
and/or via a hardware implementation, so just use gamma.
# gamma
Wiki link: <http://en.wikipedia.org/wiki/Gamma_function>
Extension of the factorials to the real numbers because:
- on the positive integergs:
gamma(n+1) == n!
- on the positive reals:
gamma(x+1) == x * gamma(x)
Has a holomorphic continuation to all imaginary plane, with poles on 0 and negative integers.
Implemented in C as `tgamma`.
# tgamma
True Gamma function. TODO0 Why True?
Computes the gamma function.
ANSI C says that it gives either domain or pole error on the negative integers.
# lgamma
lgamma = ln tgamma
*/
{
assert(fabs(tgamma(5.0) - 4*3*2 ) < err);
assert(fabs(tgamma(3.5) - 2.5 * tgamma(2.5) ) < err);
errno = 0;
volatile double d = tgamma(-1.0);
if (math_errhandling & MATH_ERRNO) {
if (errno == ERANGE)
assert(d == HUGE_VAL);
else
assert(errno == EDOM);
}
assert(fabs(lgamma(3.5) - log(tgamma(3.5))) < err);
}
/* Floating point manipulation functions. */
{
/*
# ldexp
ldexp(x, y) = x * (2^y)
*/
{
assert(fabs(ldexp(1.5, 2.0) - 6.0) < err);
}
/*
# nextafter
Return the next representable value in a direction.
If both arguments equal, return them.
# nexttowards
TODO0 diff from nextafter
*/
{
printf("nexttowards(0.0, 1.0) = %a\n", nexttoward(0.0, 1.0));
assert(nexttoward(0.0, 0.0) == 0.0);
printf("nextafter (0.0, 1.0) = %a\n", nextafter(0.0, 1.0));
}
}
/*
# random
# srand
Seed the random number generator.
It is very common to seed with `time(NULL)` for simple applications.
# rand
Get a uniformly random `int` between 0 and RAND_MAX.
For cryptographic applications, use a library:
http://crypto.stackexchange.com/questions/15662/how-vulnerable-is-the-c-rand-in-public-cryptography-protocols
On Linux, `/dev/random` is the way to go.
Intel introduced a RdRand in 2011, but as of 2015 it is not widely used,
and at some point was used as part of the entropy of `/dev/random`.
*/
{
srand(time(NULL));
/* Integer between 0 and RAND_MAX: */
{
int i = rand();
}
/* int between 0 and 99: */
{
int i = rand() % 99;
}
/* float between 0 and 1: */
float f = rand()/(float)RAND_MAX;
}
/*
# IEEE-754
IEC 60559 has the same contents as the IEEE 754-2008,
Outside of the C standard it is commonly known by the IEEE name, or simply as IEEE floating point.
IEEE dates from 1985.
# __STDC_IEC_559__
# IEC 60599
Standard on which floating point formats and operations should be available
on an implementation, and how they should work.
Good overview wiki article: <http://en.wikipedia.org/wiki/IEEE_floating_point>
Many CUPs implement large parts of IEC 60599, which C implementations can use if available.
The C standard specifies that implementing the IEC 60599 is not mandatory.
If the macro `__STDC_IEC_559__` is defined this means that the implementation is compliant
to the interface specified in Annex F of the C11 standard.
C99 introduced many features which allow greater conformance to IEC 60599.
*/
{
#ifdef __STDC_IEC_559__
puts("__STDC_IEC_559__");
/*
C float is 32 bits, double 64 bits.
long double extende precision, and could be one of the format not spceified by IEC.
IEC explicitly allows for extended formats, and makes basic restrictions such that
its exponent should have more bits than the preceding type.
This is probably the case to accomodate x86's 80 bit representation.
*/
{
assert(sizeof(float) == 4);
assert(sizeof(double) == 8);
}
#endif
}
/*
# division by 0
Time to have some fun and do naughty things.
The outcome of a division by zero depends on wether it is an integer of floating operation.
# isfinite
# isinf
# isnan
# isnormal
# fpclassify
FP_INFINITE, FP_NAN, FP_NORMAL, FP_SUBNORMAL, FP_ZERO
*/
{
/*
# floating point exception
In x86, the following generates a floating point exception,
which is handled by a floating point exception handler function.
In Linux the default handler is implemented by the OS and sends a signal to our application,
which if we don't catch will kill us.
*/
if (0) {
/* gcc 4.7 is smart enough to warn on literal division by 0: */
{
/*int i = 1 / 0;*/
}
/* gcc 4.7 is not smart enough to warn here: */
{
volatile int i = 0;
printf("int 1/0 = %d\n", 1 / i);
/* On gcc 4.7 with `-O3` this may not generate an exception, */
/* as the compiler replaces 0 / X by 0. */
printf("int 0/0 = %d\n", 0 / i);
}
}
/*
# HUGE_VAL
Returned on overflow.
Can equal `INFINITY`.
*/
{
/* double */
printf("HUGE_VAL = %f\n", HUGE_VAL);
/* float */
printf("HUGE_VALF = %f\n", HUGE_VALF);
/* long double */
printf("HUGE_VALL = %Lf\n", HUGE_VALL);
}
/*
# INFINITY
Result of operations such as:
1.0 / 0.0
Type: float.
There are two infinities: positive and negative.
It is possible that `INFINITY == HUGE_VALF`.
*/
{
printf("INFINITY = %f\n", INFINITY);
printf("-INFINITY = %f\n", -INFINITY);
volatile float f = 0;
assert(1 / f == INFINITY);
assert(isinf(INFINITY));
assert(! isnan(INFINITY));
assert(INFINITY + INFINITY == INFINITY);
assert(INFINITY + 1.0 == INFINITY);
assert(INFINITY - 1.0 == INFINITY);
assert(isnan(INFINITY - INFINITY));
assert(INFINITY * INFINITY == INFINITY);
assert(INFINITY * -INFINITY == -INFINITY);
assert(INFINITY * 2.0 == INFINITY);
assert(INFINITY * -1.0 == -INFINITY);
assert(isnan(INFINITY * 0.0));
assert(1.0 / INFINITY == 0.0);
assert(isnan(INFINITY / INFINITY));
/* Comparisons with INFINITY all work as expected. */
assert(INFINITY == INFINITY);
assert(INFINITY != - INFINITY);
assert(-INFINITY < - 1e100);
assert(1e100 < INFINITY);
}
/*
# NAN
Not a number.
Result of operations such as:
0.0 / 0.0
INFINITY - INFINITY
INFINITY * 0.o
INFINITY / INFINITY
And any operation involving NAN.
The sign of NAN has no meaning.
*/
{
printf("NAN = %f\n", NAN);
printf("-NAN = %f\n", -NAN);
/* TODO why do both fail? */
/*assert(0 / f == -NAN);*/
/*assert(0 / f == NAN);*/
volatile float f = 0;
assert(isnan(0 / f));
assert(isnan(NAN));
assert(! isinf(NAN));
assert(isnan(NAN));
assert(isnan(NAN + 1.0));
assert(isnan(NAN + INFINITY));
assert(isnan(NAN + NAN));
assert(isnan(NAN - 1.0));
assert(isnan(NAN * 2.0));
assert(isnan(NAN / 1.0));
assert(isnan(INFINITY - INFINITY));
assert(isnan(INFINITY * 0.0));
assert(isnan(INFINITY / INFINITY));
/*
NAN is not ordered. any compairison to it yields false!
This is logical since 0 is neither smaller, larger or equal to NAN.
*/
{
assert(! (0.0 < NAN));
assert(! (0.0 > NAN));
assert(! (0.0 == NAN));
}
}
}
}
#if __STDC_VERSION__ >= 199901L
/*
# stdint.h
contains several types of ints, including fixed size
and optimal for speed types
c99
all macros with numbers are defined for N = 8, 16, 32, 64
*/
{
#include <stdint.h>
/* Exactly 32 bits. */
assert(sizeof(int32_t) == 4);
/* All have unsigned verions prefixed by 'u'. */
assert(sizeof(uint32_t) == 4);
/* At least 32 bits. */
assert(sizeof(int_least32_t) >= 4);
/* Fastest operations with at least 32 bits. */
assert(sizeof(int_least32_t) >= 4);
/*
# intptr_t
An integer type large enough to hold a pointer.
Could be larger than the minimum however.
# uintptr_t
Unsigned version.
TODO0 example of real life application?
*/
{
assert(sizeof(void*) == sizeof(intptr_t));
assert(sizeof(void*) == sizeof(uintptr_t));
}
/* Uniquely defined by machine address space. */
/*
# intmax_t #uintmax_t
int with max possible width
[there is no floating point version](http://stackoverflow.com/questions/17189423/how-to-get-the-largest-precision-floating-point-data-type-of-implemenation-and-i/17189562?noredirect=1#comment24893431_17189562)
for those macros
*/
{
assert(sizeof(intmax_t) >= sizeof(long long));
assert(sizeof(uintmax_t) >= sizeof(unsigned long long));
}
/* inttypes also includes limits for each of the defined types: */
{
{
int32_t i = 0;
assert(INT32_MIN < i);
assert(INT32_MAX > i);
}
{
int_fast32_t i = 0;
assert(INT_FAST32_MIN < i);
assert(INT_FAST32_MAX > i);
}
}
/* All have max/min ranges. */
/* "_t" removed, "_max" or "_min" appended, all uppercased */
}
#endif
/*
# limits.h
Gives the maximum and minimum values that fit into base integer types
in the current architecure
*/
{
puts("limits.h");
/*
# CHAR_BIT
Numbers of bits in a char.
POSIX fixes it to 8 TODO reference.
But it is very rare to finda a system where it will not be 8.
`sizeof` returns results in multiples of it.
*/
printf(" CHAR_BIT = %d\n", CHAR_BIT);
/* Guaranteed. */
assert(CHAR_BIT >= 8);
/* TODO Not determined by CHAR_BIT? */
printf(" CHAR_MAX = %d\n", CHAR_MAX);
/* # INT_MAX */
printf(" INT_MAX = %d\n", INT_MAX);
printf(" INT_MIN = %d\n", INT_MIN);
printf(" LONG_MAX = %ld\n", LONG_MAX);
printf(" LLONG_MIN = %lld\n", LLONG_MIN);
/*
Unsigned versions are prefiexed by `U`.
There is no MIN macro for unsigned versions since it is necessarily `0`.
*/
printf(" UINT_MAX = %u\n", UINT_MAX);
}
/*
# float.h
Gives characteristics of floating point numbers and of base numerical operations
for the current architecture
All macros that start with FLT have versions starting with:
- DBL for `double`
- LDBL for `long double`
*/
{
puts("float.h");
/*
# FLT_ROUNDS
rounding method of sums
values:
- -1: indeterminable
- 0: toward zero
- 1: to nearest
- 2: toward positive infinity
- 3: toward negative infinity
TODO0 can it be changed?
*/
{
printf(" FLT_ROUNDS = %d\n", FLT_ROUNDS);
}
/*
# FLT_EVAL_METHOD
Precision to which floating point operations are evaluated
it seems that floating operations on, say, floats can be evaluated
as long doubles always.
TODO0 understand better
*/
{
printf(" FLT_EVAL_METHOD = %d\n", FLT_EVAL_METHOD);
}
/*
# FLT_MIN
Smalles positive number closes to zero that can be represented in a normal float.
Any number with absolute value smaller than this is subnormal,
and support is optional.
*/
{
printf(" FLT_MIN = %a\n", FLT_MIN);
printf(" DBL_MIN = %a\n", DBL_MIN);
printf(" LDBL_MIN = %La\n", LDBL_MIN);
}
/*
# FLT_RADIX
several other macros expand to the lengths of the representation
useful terms:
1.01_b * b ^ (10)_b
- radix:
TODO0 wow, there are non radix 2 representation implementations?!
*/
{
printf(" FLT_RADIX = %d\n", FLT_RADIX);
}
#if __STDC_VERSION__ >= 201112L
/*
# subnormal numbers
C11
Defined in IEC 60599.
Ex:
0.01
Is represented as:
1 * 10^-2
However the exponent has a fixed number of bits, so if the exponent is too small.
A solution to incrase that exponent is to allow number that start with 0.
So if for example -4 is the smallest possible exponent, 10^-5 could be represented as:
0.1 * 10^-4
Such a number that cannot be represented without trailling zeroes is a subnormal number.
The tradeoff is that subnormal numbers have limited precision.
C11 specifies that the implementation of such feature is options,
and oe can check if those are supported in the implementation via the `HAS_SUBNORM` macros.
As of 2013 hardware support is low but starting to appear.
Before this date, implementations are done on software, and are therefore slow.
The smallest floating normal number is `FLT_MIN`.
Values:
- -1: undeterminable
- 0: no
- 1: yes
*/
{
printf(" FLT_HAS_SUBNORM = %d\n", FLT_HAS_SUBNORM);
printf(" DBL_HAS_SUBNORM = %d\n", DBL_HAS_SUBNORM);
printf(" LDBL_HAS_SUBNORM = %d\n", LDBL_HAS_SUBNORM);
assert(isnormal(LDBL_MIN));
if (LDBL_HAS_SUBNORM) {
long double ldbl_min_2 = LDBL_MIN / 2.0;
printf(" LDBL_MIN / 2.0 = %La\n", ldbl_min_2);
assert(ldbl_min_2 != 0);
assert(ldbl_min_2 != LDBL_MIN);
assert(! isnormal(ldbl_min_2));
}
}
#endif
}
/*
# fenv.h
contains flags that indicate the status of floating point related registers
TODO get some interesting and basic samples working
*/
/*
# unsigned
C has unsigned versions of all built-in data types.
These basically have more or less double the maximum size
of the signed version, and are always positive.
You should always use unsigned sizes for quantities which must be positive such as:
- array indexes
- memory sizes (size_t)
As this will give clues to the compiler
and humans about the positive quality of your number
*/
{
/* True in 2's complement. Modulo arithmetic holds. */
{
assert((char)-1 == (char)255);
assert((unsigned char)-1 == (unsigned char)255);
assert((unsigned char)-2 == (unsigned char)254);
}
{
assert((char)0 > (char)255);
assert((unsigned char)0 < (unsigned char)255);
}
}
#if __STDC_VERSION__ >= 199901L
/*
# stdbool.h
# bool
Macro to `_Bool`.
Same rationale as `_Complex` vs `complex`.
# true
Macro to `1`.
# false
Macro to `0`.
*/
{
#include <stdbool.h>
bool b = true;
bool b2 = false;
assert(false == 0);
assert(true == 1);
}
#endif
#if __STDC_VERSION__ >= 199901L
#ifndef __STDC_NO_COMPLEX__
/*
# complex.h
Defines:
- convenient typedefs like `_Complex` and `I`
- common operations over complex types: creal, cimag, cabs, etc.
The complex types themselves are a feature of the language and shall not be described here.
There is no direct printf way to print complex numbers:
<http://stackoverflow.com/questions/4099433/c-complex-number-and-printf>
All functions provided by this header are prefixed by `c`.
<http://en.wikipedia.org/wiki/Tgmath.h#Complex_numbers>
# complex vs _Complex
`complex` is a typedef to `_Complex` contained in this header.
The actual type keyword is `_Complex`: the language could not add
a `complex` keyword because it could conflict with older programs.
Adding `_Complex` however is fine because it is a reserved identifier.
Prefer using `complex`: in the future it may become an actual keyword.
It is easier to read and write.
# I vs _Complex_I
TODO
# _Imaginary
Defined in non normative section of C11.
TODO vs complex?
*/
{
#include <complex.h>
const double err = 10e-6;
/* Typedef to literal. There is not explicit literal in the language. */
assert(I == _Complex_I);
const double complex zd = 1.0 + 2.0*I;
const double complex zd2 = 1.0 + 1.0*I;
assert(sizeof(float complex ) <= sizeof(double complex));
assert(sizeof(double complex) <= sizeof(long double complex));
/* Real and imaginary parts. */
assert(creal(zd) == 1.0);
assert(cimag(zd) == 2.0);
/* Subtraction. */
assert(creal(zd - zd2) == 0.0);
assert(cimag(zd - zd2) == 1.0);
/* Multiplication. */
assert(creal(zd * zd) == -3.0);
assert(cimag(zd * zd) == 4.0);
/* Division. */
assert(creal(zd / zd) == 1.0);
assert(cimag(zd / zd) == 0.0);
/* Conjugation. */
assert(creal(conj(zd)) == 1.0);
assert(cimag(conj(zd)) == -2.0);
/* absolute value == norm == module */
assert(abs(cabs(3.0 + 4.0 * I) - 5.0) < err);
/*
# csqrt
Unlike sqrt, can return imaginary outputs and take imaginary inputs.
*/
{
assert(cabs(csqrt(-1.0) - I) < err);
}
/*
# cproj
TODO
*/
/*
# csin
TODO
*/
/*assert(cabs(csin(I) - ) < err);*/
}
#endif
#endif
#if __STDC_VERSION__ >= 201112L
/*
# noreturn.h
Defines `noreturn`, a macro to `_Noreturn`.
*/
#endif
/*
# iso646.h
Obscure header with macros that avoid using characters such as `|` or '~'
which may be hard to type on certain international keyboards.
- and: &&
- and_eq: &=
- bitand: &&
- bitor: &
- compl: |
- not: !
- not_eq: !=
- or: ||
- or_eq: |=
- xor: ^
- xor_eq: ^=
*/
{
#include <iso646.h>
assert(true and true);
}
#if __STDC_VERSION__ >= 199901L
/*
# tgmath.h
TODO
http://libreprogramming.org/books/c/tgmath/
http://carolina.mff.cuni.cz/~trmac/blog/2005/the-ugliest-c-feature-tgmathh/
*/
{
/* #include <tgmath.h> */
}
}
#endif
#ifdef PROFILE
/*
- turn off optimization if you want results to make evident sense
- even without optimization, cache access speed is hard to predict
so what you expect may be false
*/
{
loop_only_prof(n_prof_runs);
while_only_prof(n_prof_runs);
int_assign_prof(n_prof_runs);
int_sum_prof(n_prof_runs);
int_sub_prof(n_prof_runs);
int_mult_prof(n_prof_runs);
int_div_prof(n_prof_runs);
float_sum_prof(n_prof_runs);
float_sub_prof(n_prof_runs);
float_mult_prof(n_prof_runs);
float_div_prof(n_prof_runs);
func_all_prof(n_prof_runs);
inline_func_call_prof(n_prof_runs);
stack1b_prof(n_prof_runs);
stack1kb_prof(n_prof_runs);
stack1mb_prof(n_prof_runs);
heap1b_prof(n_prof_runs);
heap1kb_prof(n_prof_runs);
/* by far the slowest */
/*heap1mbProf(n_prof_runs);*/
/*
BAD:
Don't do stdout on profiling.
System time is not counted anyways.
*/
/*putsProf(n_prof_runs);*/
}
#endif
/*
# Virtual memory
# Process address space
Lets have some fun reverse engeneering the process memory space modeul used on your OS!
This is all undefined behaviour on ANSI C, but the test code is the same on all OS.
All of this reflects how the process is represented in main memory.
Check cheats on each OS to understand the results.
*/
{
int stack1;
int stack2;
void *heap;
char *text = "abc";
printf("PRIxPTR usage = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)(void*)1);
#if __STDC_VERSION__ >= 199901L
printf("# Virtual memory\n");
printf(" &env = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)getenv("HOME"));
printf(" &argv = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)argv);
printf(" &argc = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)&argc);
printf(" &stack1 = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)&stack1);
printf(" &stack2 = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)&stack2);
heap = malloc(1);
printf(" &heap = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)heap);
free(heap);
printf(" &BSS = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)&BSS);
printf(" &DATA = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)&DATA);
/* TODO why on linux this is not on the text segment, */
/* even if modification gives segfault? */
printf(" &text main = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)&main);
printf(" &text char* = %0*" PRIxPTR "\n", PRIxPTR_WIDTH, (uintptr_t)&text);
/*fflush(stdout);*/
/*text[0] = '0';*/
#endif
}
/*
# Generated assembly
The following tests are only interesting to interpret
the generated assembly code to see how you compiler does things.
*/
{
/*
Does the compiler precalculate values at compile time or not?
gcc 4.7, O0:
- asm_precalc: no
- asm_precalc_inline: no
- sin: yes TODO0 why, but not for my funcs?
*/
{
int i;
float f;
i = asm_precalc(0);
i = asm_precalc_inline(0);
f = sin(0.2);
}
}
/*
# Design patterns
A good way to learn is to look at existing libraries:
- <https://github.com/libgit2/libgit2>
*/
{
/*
# Objects
Prefix every function that acts on an object with the name of the object.
The first non return parameter of the function
should be a pointer to the struct, AKA self in many languages.
E.g., libgit 2 repository methods are all of the type:
git_repository_X(git_repository* repo, ...);
*/
/*
# Private struct fields
Use opaque structs and expose public fields through getter and setter methods.
*/
/*
# Namespaces like in C++
Prefix everything public in your entire libray with a single identifier.
E.g., in libgit2, every public identifier starts with `git_`.
Of course, with this it is not possible to omit the namespace like in C++,
but many C++ coding styles don't allow that either because it becomes confusing what is what.
*/
/*
# Inheritance
The closest substitution to inheritance is struct inclusion / composition:
typedef struct derived {
struct base* base;
}
The difference is that you cannot automatically give base methods to the inheriting class.
But even in C++, object composition is considered a more flexible approach than
inheritance and is used in some cases.
*/
}
/*
# atexit
Function gets called when process ends via `exit` or a `return` on the `main` function.
*/
{
atexit(atexit_func);
if (0) exit_func();
if (0) abort_func();
}
/*
# main return
Valid returns are:
- `EXIT_SUCCESS` or `0` to indicate success
- `EXIT_FAILURE` to indicate failure
C99: return is optional. If omited a `return 0` is added to the program.
But just always return to be C89 compatible.
*/
{
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
}