U ogromnom krajoliku računalnog programiranja, malo je jezika ostavilo tako neizbrisiv trag kao programski jezik C. Rođen iz želje da se izgradi moćniji i prijenosniji operativni sustav, C je postao temelj na kojem su izgrađena bezbrojna tehnološka dostignuća. Njegova bliska povezanost s operativnim sustavom UNIX, koji je dijelio njegovu filozofiju jednostavnosti i elegancije, dodatno je učvrstila njegovo mjesto u povijesti računalstva.
Priča o C-u počinje ranih 1970-ih kada je Dennis Ritchie, istraživač Bell Labsa, nastojao razviti operativni sustav koji bi se mogao lako prenijeti na različite računalne arhitekture. Kako bi postigao ovaj cilj, Ritchie je trebao jezik koji kombinira kontrolu niske razine s apstrakcijom visoke razine – jezik koji bi mogao izraziti složene ideje, a istovremeno dopuštati izravnu manipulaciju hardverom.
Nadahnut ranijim programskim jezikom B, Ritchie je krenuo u stvaranje novog jezika koji će postati prethodnik C-u. Sa svojom sažetom sintaksom i snažnim značajkama, C je brzo stekao popularnost među programerima. Njegova sposobnost učinkovitog pristupa memoriji, upravljanja pokazivačima i interakcije s hardverom učinila ga je idealnim za sistemsko programiranje.
U međuvremenu, u Bell Labsu, grupa vizionara, uključujući Kena Thompsona i Briana Kernighana, radila je na razvoju operativnog sustava UNIX. Prepoznavši potencijal C-a, donijeli su hrabru odluku da preprave UNIX u samom jeziku. Ovaj ključni trenutak označio je rođenje duboke i trajne veze između C-a i UNIX-a.
Brak između C-a i UNIX-a bio je idealan spoj. UNIX je pružio robusnu i fleksibilnu platformu za razvoj C-a, dok je C ponudio potrebne alate za izgradnju i poboljšanje operativnog sustava. Kako se UNIX širio na razne institucije i sveučilišta, tako se i koristio C. Njegova jednostavnost, učinkovitost i prenosivost učinile su ga jezikom izbora za razvoj softvera, učvrstivši njegovu reputaciju moćnog i svestranog alata.
Simbiotski odnos između C i UNIX-a doveo je do razvoja brojnih kultnih softvera i tehnologija. Sam jezik C doživio je doradu, objavljivanjem “Programskog jezika C” Kernighana i Ritchieja 1978., koji se obično naziva “K&R C.” Ova je knjiga postala konačan vodič za C programiranje, oblikujući način na koji su generacije programera pristupale jeziku.
Kako je vrijeme prolazilo, C i UNIX nastavili su se zajedno razvijati i napredovati. Utjecaj C-a proširio se izvan UNIX ekosustava, postavši jezik izbora za operativne sustave kao što su Windows, Linux i macOS. Njegov se utjecaj proširio na različite domene, uključujući ugrađene sustave, razvoj igara i znanstveno računalstvo.
Danas, desetljećima nakon njegovog početka, naslijeđe C-a i njegova veza s UNIX-om ostaju jaki. Nebrojeni programeri još uvijek prihvaćaju eleganciju i snagu jezika, a sustavi slični UNIX-u i dalje pružaju plodno tlo za nastavak evolucije C-a.
Povijest programskog jezika C i njegove duboko ukorijenjene veze s operativnim sustavom UNIX služe kao dokaz transformativne moći suradnje, jednostavnosti i elegantnog dizajna. Dok se krećemo kroz krajolik tehnologije koji se stalno mijenja, nemojmo zaboraviti dubok utjecaj C-a i UNIX-a, čiji je spoj postavio temelje za digitalni svijet u kojem danas živimo.
Ovo su moje kratke bilješke:
GCC kompilacija
compile
//compile single file: gcc hello_world.c //produces a.out executable //specify ouput file name: gcc -o elf hello_world.c //produces file: elf //compile multiple .c files gcc -o elf part_one.c part_two.c
compile with debug data
// use '-g' option to enable debug data needed for valgrind gcc -g hello_world.c // to see all warnings gcc -Wall hello_world.c // pedantic gcc -pedantic hello_world.c // version -std=c89, -std=c99, -std=c11 gcc -std=c89 hello_world.c
macro as cli arg
#ifdef MY_MOD_ENABLE_FEATURE #define SIZE_FEATURE 1212 #endif //then compile your code with -D: gcc proggy.c -DMY_MOD_ENABLE_FEATURE
static linking / static library
gcc -c iff.c //create iff.o object ar clq libiff.a iff.o //create static library libiff.a //compile hello.c with libiff.a gcc -o hello hello.c -L ./ -liff //-L adds location, while lib name is: -l + lib[iff].a
shared object / shared library
gcc -shared -o iff.so iff.c //compile with piggy.so gcc -o hello hello.c ./piggy.so
optimise
To get warning about uninitialized variables, use: $ gcc -O -Wall -Wextra foo.c
bash script: basic compile
usage: $./compile <filename> #!/bin/bash LIBS=$(pkg-config --cflags --libs gtk+-2.0) FILE_NAME=$(echo $1 | sed 's/.\///') gcc -g -o ${FILE_NAME%.*}.elf $1 $LIBS
bash script: compile multiple
usage: $./compile.sh #filename: compile.sh #!/bin/bash SRC_FILES="boa.c boa.h main.c" OBJ_FILES="boa.o main.o" RM_FILES="boa.o main.o boa.h.gch" # compile for SRCFILE in $SRC_FILES do gcc -g -O0 -c $SRCFILE done # build gcc -g -O0 -o elf $OBJ_FILES # clean rm $RM_FILES
Tipovi
Svi tipovi
_Bool (bool) - hold 0/1 false/true char - can hold one ascii char (0-255) integer types: char short int int long int long long int unsigned integer types: unsigned char unsigned short int unsigned int unsigned long int unsigned long long int real floating types: float double long double (c11) complex types: float _Complex double _Complex long double _Complex empty type void qualifiers const volatile restrict
Veličine
Byte = 8 bits (bit is binary number) Kilobyte (KB) = 1024 bytes Megabyte (MB) = 1024 Kilobytes Gigabyte (GB) = 1024 Megabytes Terabyte (TB) = 1024 Gigabytes Petabyte (PB) = 1024 Terabytes Exabyte (EB) = 1024 Petabytes Zettabyte (ZB) = 1024 Exabytes Yottabyte (YB) = 1024 Zettabytes Depends on platform: linux 64bit, gcc (GCC) 5.3.0: char (1byte, 8 bit) -128...127 unsigned char (1byte, 8 bit) 0...255 short (2byte, 16 bit) -32768...32767 unsigned short (2byte, 16 bit) 0...65535 int (4byte, 32 bit) -2147483648...2147483647 unsigned int (4byte, 32 bit) 0...4294987295 long (8byte, 64 bit) unsigned long (8byte, 64 bit) 0...18446744073709551615 long long, singned/unsigned, same as long float (4byte, 32 bit) ±1.2×10-38 to ±3.4×1038 double (8byte, 64 bit) ±2.3×10-308 to ±1.7×10308 OR alias to float for AVR. long double (16byte, 128 bit) (ARM: 8, AVR: 4, x86: 10, x64: 16bit)
Konverzija
converting real to integer type, fractional part is lost printf("%d\n", (int) 33.424); // => 33 int int01 = 2.3434; // => 2 float fractional part can hold 6 digits float f = 9.999999; so when double gets downcasted to float (linux 64/gcc): double g = 9.9999999999; printf("%f\n", (float) g);// => 10.000000
Realni brojevi (float/double)
Interno se brojevi s pomičnim zarezom pohranjuju u dva dijela: razlomak (ili mantisa) i eksponent. Ako su to M i E, vrijednost pomičnog zareza broj je dan kao M x 2E. Na primjer, broj 0,375 pohranjen je kao mantisa 0,75 i eksponent -1. Dostupan je samo ograničen broj bitova pohraniti eksponent i mantisu. Uzmimo, kao primjer, raspored broja s pomičnim zarezom u riječi od samo 8 bita. Odlučili smo se za trobitni eksponent i pet bitna mantisa. Ovaj raspored je shematski (pravi prikaz je drugačiji, pogledajte knjigu na računalu arhitektura za sve detalje): eksponent: mantisa: [E2][E1][E0] [M4][M3][M2][M1][M0] Bitovi su numerirani tako da je bit najmanje važnosti krajnji desni bit svake od mantise i eksponenta. Pretpostavljamo da eksponent pohranjuje brojeve s komplementom dvojke. Bitni uzorak za -1 je stoga 111. Mantisa je raspoređena tako da najvažniji bit M4 broji polovice, sljedeći bit M3 broji četvrtinu, i tako dalje. Stoga, bit uzorak za 0,75 je 11000. Predstavljanje 0,375 kao 8-bitni broj s pomičnim zarezom je stoga kao što je prikazano u nastavku: eksponent: mantisa: [1][1][1] [1][1][0][0][0] Tipično, eksponent ima raspon od 10+-300, a mantisa ima oko 15 znamenki preciznost. Posljedica ograničene preciznosti mantise je da su brojevi s pomičnim zarezom podskup realnih brojeva. Stoga, dva broja s pomičnim zarezom mogu se naći u C, recimo x i y, tako da x postoji nije jednako y, a između njih ne postoji broj s pomičnim zarezom dva broja. Na primjer, u jednoj C implementaciji ne postoji broj s pomičnim zarezom između: 1,000000000000000222044604925031 i: 1,000000000000000444089209850062 ili između: 345678912.0000000596046447753906 i: 345678912.0000001192092895507812 Brojevi s pomičnim zarezom zapravo prolaze kroz stvarne brojeve, iako unutra malim koracima. Stvarna veličina koraka ovisi o stroju i kompajleru. Ovaj koračno ponašanje ima niz posljedica. Prvo, mnogi brojevi ne mogu biti točno predstavljen. Na primjer, mnogi računalni sustavi ne mogu točno predstavljaju broj 0,1. Na primjer, najbliži brojevi su: 0.09999999999999999916733273153113 i: 0,1000000000000000055511151231257 Iz tog razloga brojevima s pomičnim zarezom treba pažljivo manipulirati: 0,1*10 nije nužno jednako 1,0. Na nekim je sustavima veći od 1; na drugima je manji od 1. Test jednakosti brojeva s pomičnim zarezom, na primjer a==0.1, vjerojatno također neće dati očekivani rezultat.
Pointer
void* adresira bilo koju vrstu osim pointer funkcije
double d = 23.231; double *d1 = &d; double **d2 = &d1; //void** is used only as pointer to void* //so to pass double pointer to void use regular void* void *v1 = d2; double **d3 = (double**) v1; printf("%g\n", **d3 );
cast void pointer u drugi tip
void *data; //cast to const void ptr: (const void *) data; //cast from struct: double *double_ptr = ((double*) struct->vector); //if struct->vector is array of void* pointers, you can use now double_ptr as array: printf("%g\n", double_ptr[3]); //simplify passed in dblptr for pointer arithmetic void** easypointer = (*struct)->vector; easypointer += offset;
pass to void* argument
//outside variable int func(void *arg_data){...} double number = 2.121; func(&number); //direct pass func(&(double){42.424});
otmjene deklaracije
int board[8][8]; // an array of arrays of int int **ptr; // a pointer to a pointer to int int * risks[10]; // a 10-element array of pointers to int int (* rusks)[10]; // a pointer to an array of 10 ints int *oof[3][4]; // a 3 x 4 array of pointers to int int (* uuf)[3][4]; // a pointer to a 3 x 4 array of ints int (* uof[3])[4]; // a 3-element array of pointers to 4-element arrays of int 1. The [], which indicates an array, and the (), which indicates a function, have the same precedence. This precedence is higher than that of the * indirection operator, which means that the following declaration makes risks an array of pointers rather than a pointer to an array: int * risks[10]; 2. The [] and () associate from left to right. This next declaration makes goods an array of 12 arrays of 50 ints, not an array of 50 arrays of 12 ints: int goods[12][50]; 3. Both [] and () have the same precedence, but because they associate from left to right, the following declaration groups * and rusks together before applying the brackets. This means that the following declaration makes rusks a pointer to an array of 10 ints: int (* rusks)[10]; ^^^^^^^^^^^^^^^^^^^^^^^^^ int *oof[3][4]; The [3] has higher precedence than the *, and, because of the left-to-right rule, it has higher precedence than the [4]. Hence, oof is an array with three elements. Next in order is [4], so the elements of oof are arrays of four elements. The * tells us that these elements are pointers. The int completes the picture: oof is a three-element array of four-element arrays of pointers to int, or, for short, a 3x4 array of pointers to int. Storage is set aside for 12 pointers. int (* uuf)[3][4]; The parentheses cause the * modifier to have first priority, making uuf a pointer to a 3x4 array of ints. Storage is set aside for a single pointer. ^^^^^^^^^^^^^^^^^^^^^^^^^ char * fump(); // function returning pointer to char char (* frump)(); // pointer to a function that returns type char char (* flump[3])(); // array of 3 pointers to functions that // return type char You can use typedef to build a sequence of related types: typedef int arr5[5]; typedef arr5 * p_arr5; typedef p_arr5 arrp10[10]; arr5 togs; // togs an array of 5 int p_arr5 p2; // p2 a pointer to an array of 5 int arrp10 ap; // ap an array of 10 pointers to array-of-5-int
adresa elementa niza
int a[3]; int* b = &a[1]; //get address of element at index 1
printf
printf
int printf(const char *format, ...) Parameters format − This is the string that contains the text to be written to stdout. It can optionally contain embedded format tags that are replaced by the values specified in subsequent additional arguments and formatted as requested. Format tags prototype is %[flags][width][.precision][length]specifier, which is explained below: specifier Output c Character d or i Signed decimal integer e Scientific notation (mantissa/exponent) using e character E Scientific notation (mantissa/exponent) using E character f Decimal floating point g Uses the shorter of %e or %f G Uses the shorter of %E or %f o Signed octal s String of characters u Unsigned decimal integer x Unsigned hexadecimal integer X Unsigned hexadecimal integer (capital letters) p Pointer address n Nothing printed % Character flags Description - Left-justify within the given field width; Right justification is the default (see width sub-specifier). + Forces to precede the result with a plus or minus sign (+ or -) even for positive numbers. By default, only negative numbers are preceded with a -ve sign. (space) If no sign is going to be written, a blank space is inserted before the value. # Used with o, x or X specifiers the value is preceded with 0, 0x or 0X respectively for values different than zero. Used with e, E and f, it forces the written output to contain a decimal point even if no digits would follow. By default, if no digits follow, no decimal point is written. Used with g or G the result is the same as with e or E but trailing zeros are not removed. 0 Left-pads the number with zeroes (0) instead of spaces, where padding is specified (see width sub-specifier). width Description (number) Minimum number of characters to be printed. If the value to be printed is shorter than this number, the result is padded with blank spaces. The value is not truncated even if the result is larger. * The width is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted. .precision Description .number For integer specifiers (d, i, o, u, x, X) − precision specifies the minimum number of digits to be written. If the value to be written is shorter than this number, the result is padded with leading zeros. The value is not truncated even if the result is longer. A precision of 0 means that no character is written for the value 0. For e, E and f specifiers − this is the number of digits to be printed after the decimal point. For g and G specifiers − This is the maximum number of significant digits to be printed. For s − this is the maximum number of characters to be printed. By default all characters are printed until the ending null character is encountered. For c type − it has no effect. When no precision is specified, the default is 1. If the period is specified without an explicit value for precision, 0 is assumed. .* The precision is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted. length Description h The argument is interpreted as a short int or unsigned short int (only applies to integer specifiers: i, d, o, u, x and X). l The argument is interpreted as a long int or unsigned long int for integer specifiers (i, d, o, u, x and X), and as a wide character or wide character string for specifiers c and s. L The argument is interpreted as a long double (only applies to floating point specifiers: e, E, f, g and G). additional arguments − Depending on the format string, the function may expect a sequence of additional arguments, each containing one value to be inserted instead of each %-tag specified in the format parameter (if any). There should be the same number of these arguments as the number of %-tags that expect a value. Return Value If successful, the total number of characters written is returned. On failure, a negative number is returned.
sprintf – to string
char dest_string[3]; sprintf(dest_string, "%x", 256);
fprintf stderr – error messages
fprintf(stderr, "Memory error!\n"); exit(EXIT_FAILURE);
Datotečni I/O
Učitaj datoteku
char *das_load_text(char *__filename){ FILE *f; char *text; size_t size; f = fopen(__filename, "r"); if(f == NULL) return NULL; fseek(f, 0, SEEK_END); size = ftell(f); rewind(f); text = malloc(size + 1); size = fread(text, 1, size, f); fclose(f); text[size] = 0; return text; }
dodaj liniju
void append_line(char *filename, char *line) { FILE *fp; fp = fopen(filename ,"a+"); fprintf(fp, line); fclose(fp); }
i/o modovi
Mode String "r" Open a text file for reading. "w" Open a text file for writing, truncating an existing file to zero length, or creating the file if it does not exist. "a" Open a text file for writing, appending to the end of an existing file, or creating the file if it does not exist. "r+" Open a text file for update (that is, for both reading and writing). "w+" Open a text file for update (reading and writing), first truncating the file to zero length if it exists or creating the file if it does not exist. "a+" Open a text file for update (reading and writing), appending to the end of an existing file, or creating the file if it does not yet exist; the whole file can be read, but writing can only be appended. "rb", "wb", "ab", "ab+", "a+b", "wb+", "w+b", "ab+", "a+b" Like the preceding modes, except it uses binary mode instead of text mode. For systems such as Unix and Linux that have just one file type, the modes with the b are equivalent to the corresponding modes lacking the b.
Terminal
pošalji izlaz u drugi termial
Open terminal and find out where it is by typing: $ tty => /dev/pts/5 Now open another and type: $ echo "ekko" > /dev/pts/5 This should print "ekko" in /dev/pts/5 In C you could use: void memerr(){ FILE *f = fopen("/dev/pts/5", "w"); fprintf(f, "%s\n", "Memory Error!"); } Which is same as above. Also you can use cat command to clear target terminal.
argumenti naredbenog retka
char *fg = NULL; char *bg = NULL; char *close = NULL; if (argc != 7){ help(); } else { for (int i=1; i<argc; i++){ if ( (memcmp(argv[i], "-f", 2) == 0) ) fg = argv[i+1]; else if ( (memcmp(argv[i], "-b", 2) == 0) ) bg = argv[i+1]; else if ( (memcmp(argv[i], "-c", 2) == 0) ) close = argv[i+1]; } if (!fg) help(); if (!bg) help(); if (!close) help(); }
bitwise operatori
osnovno
// byte (char type) has 8 smaller bits // bit can be 1 or 0 // 01100100 // rightmost bit is low-order bit, leftmost is high-order bit // left-most is sign bit, if this bit is 1, number is negative
pozitivno ili negativno
// leftmost bit in signed types represents positive/negative boolean // 0 is positive, while 1 is negative // leftmost bit is also called signed bit 00000001 = 1 10000001 = -1 01111111 = 127 11111111 = -128
int/bin/hex/char byte tablica
INT BINARY HEX CHAR ^^^ ^^^^^^ ^^^ ^^^^ [000] 00000000 0x0 \0 [001] 00000001 0x1 SOH [002] 00000010 0x2 STX [003] 00000011 0x3 ETX [004] 00000100 0x4 EOT [005] 00000101 0x5 [006] 00000110 0x6 ACK [007] 00000111 0x7 [008] 00001000 0x8 \b [009] 00001001 0x9 \t [010] 00001010 0xa \n [011] 00001011 0xb [012] 00001100 0xc [013] 00001101 0xd \r [014] 00001110 0xe [015] 00001111 0xf [016] 00010000 0x10 DLE [017] 00010001 0x11 DC1 [018] 00010010 0x12 DC2 [019] 00010011 0x13 DC3 [020] 00010100 0x14 DC4 [021] 00010101 0x15 NAK [022] 00010110 0x16 SYN [023] 00010111 0x17 ETB [024] 00011000 0x18 CAN [025] 00011001 0x19 EM [026] 00011010 0x1a SUB [027] 00011011 0x1b ESC [028] 00011100 0x1c F5 [029] 00011101 0x1d G5 [030] 00011110 0x1e R5 [031] 00011111 0x1f US [032] 00100000 0x20 WHITESPACE [033] 00100001 0x21 ! [034] 00100010 0x22 " [035] 00100011 0x23 # [036] 00100100 0x24 $ [037] 00100101 0x25 % [038] 00100110 0x26 & [039] 00100111 0x27 ' [040] 00101000 0x28 ( [041] 00101001 0x29 ) [042] 00101010 0x2a * [043] 00101011 0x2b + [044] 00101100 0x2c , [045] 00101101 0x2d - [046] 00101110 0x2e . [047] 00101111 0x2f / [048] 00110000 0x30 0 [049] 00110001 0x31 1 [050] 00110010 0x32 2 [051] 00110011 0x33 3 [052] 00110100 0x34 4 [053] 00110101 0x35 5 [054] 00110110 0x36 6 [055] 00110111 0x37 7 [056] 00111000 0x38 8 [057] 00111001 0x39 9 [058] 00111010 0x3a : [059] 00111011 0x3b ; [060] 00111100 0x3c < [061] 00111101 0x3d = [062] 00111110 0x3e > [063] 00111111 0x3f ? [064] 01000000 0x40 @ [065] 01000001 0x41 A [066] 01000010 0x42 B [067] 01000011 0x43 C [068] 01000100 0x44 D [069] 01000101 0x45 E [070] 01000110 0x46 F [071] 01000111 0x47 G [072] 01001000 0x48 H [073] 01001001 0x49 I [074] 01001010 0x4a J [075] 01001011 0x4b K [076] 01001100 0x4c L [077] 01001101 0x4d M [078] 01001110 0x4e N [079] 01001111 0x4f O [080] 01010000 0x50 P [081] 01010001 0x51 Q [082] 01010010 0x52 R [083] 01010011 0x53 S [084] 01010100 0x54 T [085] 01010101 0x55 U [086] 01010110 0x56 V [087] 01010111 0x57 W [088] 01011000 0x58 X [089] 01011001 0x59 Y [090] 01011010 0x5a Z [091] 01011011 0x5b [ [092] 01011100 0x5c \ [093] 01011101 0x5d ] [094] 01011110 0x5e ^ [095] 01011111 0x5f _ [096] 01100000 0x60 ` [097] 01100001 0x61 a [098] 01100010 0x62 b [099] 01100011 0x63 c [100] 01100100 0x64 d [101] 01100101 0x65 e [102] 01100110 0x66 f [103] 01100111 0x67 g [104] 01101000 0x68 h [105] 01101001 0x69 i [106] 01101010 0x6a j [107] 01101011 0x6b k [108] 01101100 0x6c l [109] 01101101 0x6d m [110] 01101110 0x6e n [111] 01101111 0x6f o [112] 01110000 0x70 p [113] 01110001 0x71 q [114] 01110010 0x72 r [115] 01110011 0x73 s [116] 01110100 0x74 t [117] 01110101 0x75 u [118] 01110110 0x76 v [119] 01110111 0x77 w [120] 01111000 0x78 x [121] 01111001 0x79 y [122] 01111010 0x7a z [123] 01111011 0x7b { [124] 01111100 0x7c | [125] 01111101 0x7d } [126] 01111110 0x7e ~ [127] 01111111 0x7f [128] 10000000 0x80 [129] 10000001 0x81 [130] 10000010 0x82 [131] 10000011 0x83 [132] 10000100 0x84 [133] 10000101 0x85 [134] 10000110 0x86 [135] 10000111 0x87 [136] 10001000 0x88 [137] 10001001 0x89 [138] 10001010 0x8a [139] 10001011 0x8b [140] 10001100 0x8c [141] 10001101 0x8d [142] 10001110 0x8e [143] 10001111 0x8f [144] 10010000 0x90 [145] 10010001 0x91 [146] 10010010 0x92 [147] 10010011 0x93 [148] 10010100 0x94 [149] 10010101 0x95 [150] 10010110 0x96 [151] 10010111 0x97 [152] 10011000 0x98 [153] 10011001 0x99 [154] 10011010 0x9a [155] 10011011 0x9b [156] 10011100 0x9c [157] 10011101 0x9d [158] 10011110 0x9e [159] 10011111 0x9f [160] 10100000 0xa0 [161] 10100001 0xa1 [162] 10100010 0xa2 [163] 10100011 0xa3 [164] 10100100 0xa4 [165] 10100101 0xa5 [166] 10100110 0xa6 [167] 10100111 0xa7 [168] 10101000 0xa8 [169] 10101001 0xa9 [170] 10101010 0xaa [171] 10101011 0xab [172] 10101100 0xac [173] 10101101 0xad [174] 10101110 0xae [175] 10101111 0xaf [176] 10110000 0xb0 [177] 10110001 0xb1 [178] 10110010 0xb2 [179] 10110011 0xb3 [180] 10110100 0xb4 [181] 10110101 0xb5 [182] 10110110 0xb6 [183] 10110111 0xb7 [184] 10111000 0xb8 [185] 10111001 0xb9 [186] 10111010 0xba [187] 10111011 0xbb [188] 10111100 0xbc [189] 10111101 0xbd [190] 10111110 0xbe [191] 10111111 0xbf [192] 11000000 0xc0 [193] 11000001 0xc1 [194] 11000010 0xc2 [195] 11000011 0xc3 [196] 11000100 0xc4 [197] 11000101 0xc5 [198] 11000110 0xc6 [199] 11000111 0xc7 [200] 11001000 0xc8 [201] 11001001 0xc9 [202] 11001010 0xca [203] 11001011 0xcb [204] 11001100 0xcc [205] 11001101 0xcd [206] 11001110 0xce [207] 11001111 0xcf [208] 11010000 0xd0 [209] 11010001 0xd1 [210] 11010010 0xd2 [211] 11010011 0xd3 [212] 11010100 0xd4 [213] 11010101 0xd5 [214] 11010110 0xd6 [215] 11010111 0xd7 [216] 11011000 0xd8 [217] 11011001 0xd9 [218] 11011010 0xda [219] 11011011 0xdb [220] 11011100 0xdc [221] 11011101 0xdd [222] 11011110 0xde [223] 11011111 0xdf [224] 11100000 0xe0 [225] 11100001 0xe1 [226] 11100010 0xe2 [227] 11100011 0xe3 [228] 11100100 0xe4 [229] 11100101 0xe5 [230] 11100110 0xe6 [231] 11100111 0xe7 [232] 11101000 0xe8 [233] 11101001 0xe9 [234] 11101010 0xea [235] 11101011 0xeb [236] 11101100 0xec [237] 11101101 0xed [238] 11101110 0xee [239] 11101111 0xef [240] 11110000 0xf0 [241] 11110001 0xf1 [242] 11110010 0xf2 [243] 11110011 0xf3 [244] 11110100 0xf4 [245] 11110101 0xf5 [246] 11110110 0xf6 [247] 11110111 0xf7 [248] 11111000 0xf8 [249] 11111001 0xf9 [250] 11111010 0xfa [251] 11111011 0xfb [252] 11111100 0xfc [253] 11111101 0xfd [254] 11111110 0xfe [255] 11111111 0xff
binarno s predznakom 256
00000001 1 00000011 3 00000111 7 00001111 15 00011111 31 00111111 63 01111111 127 11111111 255 10000000 128 11000000 192 11100000 224 11110000 240 11111000 248 11111100 252 11111110 254 11111111 255
AND operator &
1 & 0 = 0 0 & 1 = 0 0 & 0 = 0 1 & 1 = 1 00011001 25 & 01001101 77 -------- 00001001 9 To test this use python console: >>> bin(0b00011001 & 0b01001101) '0b1001' '0's are removed
Inclusive OR operator |
0|0 bits are 0 other combos are 1 0 | 0 = 0 1 | 0 = 0 0 | 1 = 1 1 | 1 = 1
Exclusive OR operator ^ (XOR)
same bits are 0 mixed combos are 1 0 | 0 = 0 1 | 0 = 1 0 | 1 = 1 1 | 1 = 0
Ones complement operator ~ (unary)
bit flip b1 ~b1 ^^^^^^^ 0 1 1 0 python console test: >>> ~0b11111111 -256 >>> 0b11111111 255 >>>
Shift operators <<, >>
char a = 1; //00000001 a <<= 7; //10000000 a >>= 7; //11111111
structure bit fields
struct packed_struct{ unsigned int :3; //3 unamed bits unsigned int f1:1; //1 bool bit unsigned int f2:1; unsigned int f3:1; unsigned int type:8; //type is 8 bits unsigned int index:18; //index is 18 };
display byte as binary
#include <stdio.h> #include <stdlib.h> #include <string.h> char *das_toByteBinary(unsigned char n) { if (n == 0){ char *s = malloc(sizeof (char) * (8+1)); if (!s) return NULL; bzero(s, 9); //nullify all memset(s, 48, 8); //set string zeros "0" return s; } int t = n; int r = 0, c = 0; //how much digits do you have? r = n % 2; c++; while (t >= 2){ t = t / 2; r = t % 2; c++; r = 0; } //malloc and store chars char *s = malloc(sizeof (char) * (8+1)); if (!s) return NULL; bzero(s, 9); //nullify all memset(s, 48, 8); //set string zeros "0" c = 7; t = n; r = n % 2; s[c--] = ('0' + r); while (t >= 2){ t = t / 2; r = t % 2; s[c--] = ('0' + r); r = 0; } return s; } unsigned char das_fromByteBinary(char *s) { return (unsigned char) strtol(s, NULL, 2); } int main(void) { char a = 123; printf("%s\n", das_toByteBinary(a)); }
moving bits
[ 1] 00000001 //char a=1; [ 64] 01000000 // a <<= 6; [ 2] 00000010 // a >>= 5; [-128] 10000000 // a <<= 6; [ -4] 11111100 // a >>= 5; [ -1] 11111111 // a >>= 5;
flags as function arguments
#define ONE 0x01 // 00000001 #define TWO 0x02 // 00000010 #define FOUR 0x04 // 00000100 #define EIGHT 0x08 // 00001000 #define TEN 0x10 // 00010000 #define TWTY 0x20 // 00100000 #define FRTY 0x40 // 01000000 #define EITY 0x80 // 10000000 void func(char __flags){ char flag = 0; flag |= __flags; if ((flag & ONE) != 0) printf("ONE \n"); if ((flag & TWO) != 0) printf("TWO \n"); if ((flag & FOUR) != 0) printf("FOUR \n"); } int main(){ func(TWO|FRTY); }
accept only arguments algorithm
//more useful for weaktyped (js/php) but can be handy with ADTs in C if (!(typeof arg === 'boolean' || arg === undefined)) return null;
Array
osnove
//arrays are dereferenced pointers int *heap_iptr = malloc(sizeof (int) * 10); // make room for 10 ints on heap int stack_arr[10]; // make room for 10 ints on stack heap_iptr[0] = 100; //is same as: *(heap_iptr+0) = 101; //address &heap_iptr[0] == heap_iptr
real number vs index number
//reserve 32 spaces of size double*32 double dbla[32] = {0}; //so index starts at 0 but ends at 31 dbla[0] = 523.566; dbla[31] = 41.23; //so when using in for loop, use < with real number and <= with index for (int i=0; i<32; i++) printf("%g\n", dbla[i]);
init array
double dbla[24] = {0}; double dbla[24]; memset(&dbla, 0, (sizeof(double) * 24)); void *a = malloc(sizeof(int)*3); a = (int [3]) {12, 16, 3}; printf("%d\n", ((int*) a)[1] ); //it's easier to dereference void pointer and then use it as array ie: int *a_ptr = (int*) a; printf("%d\n", a_ptr[1] );
resizable array (heap memory)
typedef struct Vector{ size_t array_length; double data[1]; }Vector; size_t item_number = 256; size_t malloc_size = sizeof (Vector) + ((sizeof (double)) * item_number-1); Vector *vec = malloc(malloc_size); //use realloc to resize size_t new_size = sizeof (Vector) + ((sizeof (double)) * (512-1)); vec = realloc(vec, malloc_size);
pass array to function
void funarray(int *array) { printf("%d\n", array[0]); } int main() { int a[3] = {0}; a[0] = 124; funarray(a); }
pass in function data
void accept_double_ptr(double *arg){ printf("%g\n", arg[2]); } accept_double_ptr((double*) &(double []) {.234, 42.24, 123.32, 2.5});
multi-dimensional array
const int array_2d[3][3] = { {0,1,2}, {0,1,2}, {0,1,2} };
malloc for array of pointers/strings
static char **strdata; strdata = malloc(sizeof(char*)); strdata[0] = "string";
MEMORY ALLOCATION
work with any memory
// header + data structure // data is 1 char which is 1 byte. size tells you where chunk ends //memory chunk with size //size after data[] is empty and can fit any type if you alloc enough space typedef struct Chunk{ size_t size; //size of chunk char data[1]; } Chunk; char *somedata = "Some string but it can be data type just cast it to char."; size_t malloc_size = sizeof(Chunk) + strlen(somedata) +1; //+1 to set last byte to NULL Chunk *cnk = malloc(malloc_size); //allocate heap memory memset(chk, '\0', malloc_size); //nullify all memcpy(chk, somedata, malloc_size); //copy data //you can then make more complex structure where header will point to //__data. that way you are working only with one chunk. typedef struct Chunk{ char* key; double* number; size_t size; char __data[1]; } Chunk; //or more complex grouping typedef struct Element{ unsigned int size; struct color{ int red; int green; int blue; } color[1]; } Element;
memory units
bit - 0/1 byte (char) - 8 bits byte: 7 6 5 4 3 2 1 0 * * * * * * * * 128 64 32 16 8 4 2 1 On Linux 4.3 x86_64: char: 1 byte short: 2 bytes 2 x 8 bits = 16 bit int: 4 bytes 4 x 8 bits = 32 bit long: 8 bytes 8 x 8 bits = 32 bit long long: 8 bytes 8 x 8 bits = 64 bit float: 4 bytes 4 x 8 bits = 32 bit double: 8 bytes 8 x 8 bits = 64 bit
memory editing
//copy float to float byte by byte typedef char byte; float f_src = 23.32f; float f_dst = 0; byte *f_src_b = (byte*) &f_src; byte *f_dst_b = (byte*) &f_dst; f_dst_b[0] = f_src_b[0]; f_dst_b[1] = f_src_b[1]; f_dst_b[2] = f_src_b[2]; f_dst_b[3] = f_src_b[3]; printf("%g\n", f_dst);
size_t / sizeof
// The size_t type is defined in terms of the standard C types. It is the type // returned by the sizeof operator. Typically, it is unsigned int, but an // implementation can choose another type. // sizeof is not an function but a keyword, parenthesis are cast size_t double_siz = sizeof (double); // get size for 1000 double numbers size_t double_siz = sizeof (double) * 1000; // get size for string char *str = "hello world"; size_t string_siz = strlen(str) + 1; // +1 for null terminator '\0'
malloc
#include <stdlib.h> void *malloc(size_t size); // you can allocate memory on anything pointer void *chunk = malloc(1); //allocates 1 byte (char), argument is size_t type // sizeof, sizeof is not a function, parenthesis are for cast. double *chunk = malloc(sizeof (double)); // other common way is pointer deref double *chunk = malloc(sizeof (*chunk)); // don't forget *, or you will allocate only size of pointer // after malloc check for memory error char *str = malloc(256); if (str == NULL){ fprintf(stderr, "Couldn't allocate memory.\n"); exit(EXIT_FAILURE); } // when done you should free memory back to system: free(str); // after free() set pointer to NULL. Security reasons str = NULL;
calloc
// same as malloc but usefull for allocating arrays int *heap_array = calloc(100, sizeof(int)); // arg0 is amount, arg1 is size_t
realloc
// resize allocated chunk void *realloc(void *ptr, size_t size); int *chunky = malloc(sizeof (int) * 200); int *resized = NULL; resized = realloc(chunky, sizeof (int) * 400); if (!resized){ fprintf(stderr, "Memory error!\n"); exit(EXIT_FAILURE); } // cleaner version that use function: void *reallocate(void *arg_data, size_t arg_size) { void *return_value; return_value = realloc(arg_data, arg_size); if (!return_value){ fprintf(stderr, "Memory error!\n"); exit(EXIT_FAILURE); } return return_value; }
alloca (unix)
// alloca() allocates memory chunk on stack memory // memory gets automatically freed at function end // DON'T USE free() on alloca chunk #include <alloca.h> void *alloca(size_t size);
free
int *chunky = malloc(sizeof (int) * 200); // when done you should free memory back to system: free(chunky); // after free() set pointer to NULL. Security reasons chunky = NULL; // you can reuse pointer for another allocation chunky = malloc(sizeof (int) * 50);
memset
#include <string.h> // sets memory range to int number // void *memset(void *s, int c, size_t n); int *list = malloc(sizeof (int) * 200); memset(list, 0, sizeof (int) * 200);
memcpy
#include <string.h> // copies memory range to other memory range // void *memcpy(void *dest, const void *src, size_t n); double d[] = {34.31, 12.32}; double *d_p = calloc(2, sizeof (double)); memcpy(d_p, d, sizeof (double) * 2); printf("%g\n", d_p[1]);
get size of inner struct
typedef struct Element{ unsigned int size; struct color{ int red; int green; int blue; } color[1]; } Element; int main(){ Element *elem = NULL; printf("Size of inner struct 'color': %d\n", sizeof (elem->color) ); }
struct
declare struct
// DataGroup is template tag struct DataGroup{ char key[32]; double value; }; // DON'T FORGET ';' // declare/create 'images' structure using DataGroup template struct DataGroup images; // or multiple struct DataGroup images, sounds, *vectors; // combine declaration and variable (Images) struct DataGroup{ char key[32]; double value; }Images; // without tag, structure can't be used as template struct{ char key[32]; double value; }Images;
init struct
// nullify struct DataGroup Images = {0}; // old school struct DataGroup Images = { "Here be key", //char *key; 32.422 //double value; }; // c99 designated initializers struct DataGroup Images = { .key = "Here be key", .value = 32.422 }; // or combination struct Elem { int a; int b; } elem = { .a = 1, .b = 2, };
function argument/return struct
// basic struct Element elem; func(&elem); // pass struct as argument (compound literal) struct_func((struct DataGroup) {"title", 2.34 }); // pass struct ptr as argument struct_func(&(struct DataGroup) {"title", 2.34 }); // structs are returned as copy of data struct DataGroup return_images() { return (struct DataGroup) {"title", 2.34 }; //compound literal }
struct in struct
struct { struct { int day; int month; int year; } dob; int a; int b; } Element;
opaque type
typedef struct String{ size_t length; char string[1]; }String; String *string = newString("io ox"); SEE: ABSTRACT DATATYPES
union in struct
enum{ NUMBER = 1, STRING = 2, }; struct Data { int type; //enum union{ double dbl; char *str; }; }; // int type; is header which holds info on which type union hold struct Data number; number.type = NUMBER; number.dbl = 2343.2234; // so if (number.type == NUMBER) you know that it holds number
linked structures
struct Data { double data; struct Data *next; }; //create two structs in heap struct Data *dat00 = malloc(sizeof (*dat00)); dat->data = 23.123; dat->next = NULL; struct Data *dat01 = malloc(sizeof (*dat01)); dat->data = 3.4; dat->next = NULL; //link one to another dat00->next = dat01; //access 01 data from 00 printf("%g\n", dat00->next->data);
array of structures
//create array of 256 items form Data template struct Data dat[256] = {0}; //variable only struct{ char *key; double value; } hash[1024]; hash[0].key = "window size"; hash[0].value = 100; printf("%g\n", hash[0].value); //////////////////////////////////////////////////// typedef struct Argument{ char *key; int (*action)(void); //return err code, pass in w/e }Argument; int dummy(){ printf("%s\n","wakka!");} Argument argmnt[] = { {.key="fg", .action=dummy }, {.key="bg", .action=dummy }, {.key="close", .action=dummy }, {.key=NULL, .action=NULL } //terminator };
copy stack to heap
//<string.h> for memcpy typedef struct Element{ char *key; double value; }Element; //create struct on stack Element stack_elem; stack_elem.key = "main() only"; stack_elem.value = 23.122; //copy to heap Element *heap_elem = malloc(sizeof (Element)); memcpy(heap_elem, &stack_elem, sizeof (Element));
short stack data grouping
struct {int a; double b;} list01 = {1221, 13.31};
passing anonymous struct to function
int func(void *data){ struct {int c; double d;} *p = data; printf("%g\n", p->d); } int main(){ struct {int a; double b;} list01 = {1221, 13.13}; func(&list01); printf("%g\n", list01.b); }
Linked list
basic structure
//linked list typedef struct Node{ struct Node *next; void *value; char key[1]; }Node; //double-linked list typedef struct Node{ struct Node *next; struct Node *prev; void *value; char key[1]; }Node; //node header typedef struct Header{ struct Node *head; unsigned int length; char header_name[1]; }Header;
free list
void freeNode(Node **arg_node){ if (!(*arg_node)->next){ free(*arg_node); *arg_node = NULL; } else { Node *node = *arg_node; Node *freenode = NULL; while (!node){ freenode = node; node = node->next; free(freenode); freenode = NULL; } } }
Modules and naming
module structure
[module.c] //module functions [module.h] //external interface [module.private] //private header for datatypes... [module.private] <-- [module.c] --> [module.h] --> [main.c]
naming
Module name example: topaz Datatype name: Topaz Function name: (note 'item' and 'Append' order) tpz_create(); tpz_itemAppend(); tpz_itemRemove(); tpz_destroy(); Macro name: TPZ_MACRO_NAME function argument name: arg_handle
hidding
MAKING FUNCTIONS LOCAL TO FILE [module.c] static int privateFunction(){...}; DATATYPE HIDDING [module.private]: typedef struct Topaz{int data; ...}Topaz; [module.h]: typedef void Topaz;
header defined only once
#ifndef UTIL_H #define UTIL_H your header code goes here... #endif //enable module features #ifdef MY_MOD_ENABLE_FEATURE #define SIZE_FEATURE 1212 #endif //then compile your code with -D: gcc proggy.c -DMY_MOD_ENABLE_FEATURE
Const
examples
int const a; //a constant integer int const *b; //a (variable) pointer to a constant integer int *const c; // a constant pointer to a (variable) integer int *const *d; // a pointer to a constant pointer to an integer int const **e; // a pointer to a pointer to a constant integer int const *const *f; // a pointer to a constant pointer to a constant integer //ptr const float *pf; // pf points to a constant float value float *const pt; // pt is a const pointer
Comments
examples
// use c++ comments in code so that you can encapsulate large parts of code by c's /* */ /* int a = 0; uint32_t b = 0x20; //comment */ /****************************************************************************\ SECTION \****************************************************************************/ /* --------------- Minor Section Marker --------------- */ /******************************************************** * This is a boxed comment. the box draws attention * * to it. This type of comment is used for programs, * * module and function headings. * ********************************************************/ /* ** Yes, this would be almight one-liner comment. */ /* ** Yes, this would be almight one-liner comment. ** And, I got another one, (the line that is) bellow. */ /*--------------------*\ * Another box style * \*--------------------*/ /*---------------* | Section Header | *----------------*/
stdarg
primjer
#include <stdarg.h> #include <stdio.h> double sum(int arg_length, ...) { double total = 0; va_list arg_list; // declare object to hold arguments va_start(arg_list, arg_length); // initialize arg_list to argument list int i; for (i = 0; i < arg_length; i++) total += va_arg(arg_list, double); // access each item in argument list va_end(arg_list); //clean up return total; } int main() { double number_sum; number_sum = sum(3, 1.1, 2.5, 13.3); printf("sum numbers: %g\n", number_sum); }
String
string types
//read-only stack string, this should be written as 'const char *string' char *string = "I'm a string in stack."; //read-write stack string char str[7] = "String"; /* add one extra spot for '\0' terminator */ char str[7] = {'S', 't', 'r', 'i', 'n', 'g', '\0'}; char str[] = "String"; //read-write heap string char str[] = "String"; char *heapstr = malloc(strlen(str) + 1); //+1 for '\0' memcpy(heapstr, str, strlen(str)); heapstr[strlen(str)] = '\0';
array of strings (string pointers)
void mod_str(char ***return_str, char *arg_str1, char *arg_str2) { *return_str = malloc( (sizeof (char**)) *2); (*return_str)[0] = arg_str1; (*return_str)[1] = arg_str2; printf("%s\n", (*return_str)[0] ); } int main() { char *s1 = "alpha"; char *s2 = "beta"; char **work_str = NULL; mod_str(&work_str, s1, s2); printf("w: %s\n", work_str[1] ); }
pass array of strings to function
void parse_file(char **pattern) { printf("%s\n", pattern[1]); } char *pattern[] = {"/*", "*/", "//", "\n"}; parse_file(pattern);
struct container
typedef struct String{ char *last_item; size_t length; char data[1]; //null terminator / string will just use memory space after }String; String *String_new(char *arg_string) { size_t string_size = strlen(arg_string); String *new = malloc(sizof(String) + string_size); new->length = string_size; memcpy(new, arg_string, string_size); new[string_size] = 0; return new; }
string list
const char *mytal[] = { /* array of 5 strings */ "Adding numbers swiftly", "Multiplying accurately", "Stashing data", "Following instructions to the letter", "Understanding the C language" };
heap string
char *heapstrm(char *s){ size_t len = strlen(s); size_t i = 0; char *r = malloc(len+1); memcpy(r, s, len); r[len] = '\0'; // NULL at end !!!! return r; } char *heapstr(char *s){ size_t len = strlen(s); size_t i = 0; char *r = malloc(len+1); for (; i<len; i++){ r[i] = s[i]; } r[len] = '\0'; return r; } //////////////////// char *s = heapstr("abcdefgh"); /* [0] a [1] b [2] c [3] d [4] e [5] f [6] g [7] h [8] '\0' - malloc(len+1); ie 8+1 */
GDB – debugger
compile for gdb use
gcc -g -O0 prg.c
usage
// clean up // enter repeats last command gdb ./a.out type: start list 10 lines of source (enter with list 10 more): list print variable: p in_prog_var step through whole program: s move to next line only in main(), not sub-routines: n // examine low level print (address: raw bytes), hit x again will examine at next addr+4: x in_prog_var lowlevel print singlebyte: x/b in_prog_var 10 bytes in order x/10b in_prog_var examine bytes at address: x/b 0x7fffffffe404 // watch watch variable and report when it changes watch in_prog_var to get report when variable gets reed use: rwatch in_prog_var continue till hit watch | rwatch cont see all watchpoints info watch re-starting exe clears watchpoints // breakpoints to create breakpoint use, number is line number: break 13 continue till hit break (runs and stops at line 13): cont see all breakpoints info break delete breakpoint dele 13 // callframe to see callframe use backtrace cmd: bt to check frames (context/scope): frame 0 // set variable set var in_prog_var=23 // quit q
without debug symbols (-g)
// without debug symbols (regular exes) gdb ./a.out examine 20 instructions starting at the program counter: x/20i $pc ie. <main+9> 9 bytes from beginning of prog
String
find substring, strstr()
#include <string.h> char *strstr(const char *haystack, const char *needle); //The strstr() function finds the first occurrence of the substring needle //in the string haystack. //Function returns a pointer to the beginning of the located substring, //or NULL if the substring is not found. //nonstandard strcasestr() is same but ignores case
find byte: memchr(), memrchr(), rawmemchr(), memmem()
#include <string.h> void *memchr(const void *s, int c, size_t n); void *memrchr(const void *s, int c, size_t n); void *rawmemchr(const void *s, int c); The memchr() function scans the initial n bytes of the memory area pointed to by s for the first instance of c. Both c and the bytes of the memory area pointed to by s are interpreted as unsigned char. The memrchr() function is like the memchr() function, except that it searches backward from the end of the n bytes pointed to by s instead of forward from the beginning. The rawmemchr() function is similar to memchr(): it assumes (i.e., the programmer knows for certain) that an instance of c lies somewhere in the memory area starting at the location pointed to by s, and so per‐ forms an optimized search for c (i.e., no use of a count argument to limit the range of the search). If an instance of c is not found, the results are unpredictable. //to look for group of bytes use: void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
ctype.h
#include <ctype.h> ialnum(c) Returns a non-zero if c is alphabetic or numeric isalpha(c) Returns a non-zero if c is alphabetic scntrl(c) Returns a non-zero if c is a control character isdigit(c) Returns a non-zero if c is a digit, 0 – 9 isgraph(c) Returns a non-zero if c is a non-blank but printing character islower(c) Returns a non-zero if c is a lowercase alphabetic character, i.e., a – z isprint(c) Returns a non-zero if c is printable, non-blanks and white space included ispunct(c) Returns a non-zero if c is a printable character, but not alpha, numeric, or blank isspace(c) Returns a non-zero for blanks and these escape sequences: ‘\f’, ‘\n’, ‘\r’, ‘\t’, and ‘\v’ isupper(c) Returns a non-zero if c is a capital letter, i.e., A – Z isxdigit(c) Returns a non-zero if c is a hexadecimal character: 0 – 9, a – f, or A – F tolower(c) Returns the lowercase version if c is a capital letter; otherwise returns c toupper(c) Returns the capital letter version if c is a lowercase character; otherwise returns c
strtol, string hex to long, with base
#include <stdlib.h> long int strtol(const char *nptr, char **endptr, int base); char *b = "11110000"; printf("%d\n", strtol(b, NULL, 2)); // 240 char *h = "fefefe"; printf("%d\n", strtol(h, NULL, 16)); // 16711422
int to hex string
int a = 16711422; char hex[6] = {0}; snprintf(hex, 7, "%x", a); printf("%s\n", hex); //fefefe
hex2rgb
//_array is ptr to int rgb[3], _hex is "fefefe" color string int das_hex2rgb(unsigned int *_array, char *_hex){ if (strlen(_hex) !=6) return -1; //is hex char? for (int i=0; i<strlen(_hex); i++){ if (!( (!(_hex[i]<48) && !(_hex[i]>57)) || (!(_hex[i]<65) && !(_hex[i]>70)) || (!(_hex[i]<97) && !(_hex[i]>102)) )){ printf("%s\n","Not hex!"); return -1; } } char r[3] = {0}, g[3] = {0}, b[3] = {0}; r[0] = _hex[0]; r[1] = _hex[1]; g[0] = _hex[2]; g[1] = _hex[3]; b[0] = _hex[4]; b[1] = _hex[5]; printf("%s\n", g); _array[0] = strtol(r, NULL, 16); _array[1] = strtol(g, NULL, 16); _array[2] = strtol(b, NULL, 16); return 0; }
Assert
about
void assert(int exprs); If exprs evaluates to nonzero (or true), the macro does nothing. If it evaluates to zero (false), assert() displays expression, the line number for the assert() statement, and the name of the file containing the statement. Then it calls abort().
example
#include <stdio.h> #include <assert.h> int main() { int a = 3; //abort() if expression is false, so: assert(a<0); //a is less then 0 => false => abort&report }
NDEBUG
Defining the macro identifier NDEBUG before including the assert.h header file deactivates the assert() macro. #define NDEBUG #include <assert.h> or: $ gcc proggy.c -DNDEBUG