less_retarded_wiki

main page, file list (582), source, all in md+txt+html+pdf, report abuse, stats, random article, consoomer version

C

{ We have a C tutorial! ~drummyfish }

C is an old low level structured statically typed imperative compiled programming language, it is very fast and currently mostly used by less retarded software. Though by very strict standards it would still be considered bloated, compared to any mainstream modern language it is very bullshitless, KISS and greatly established and "culturally stable", so it is also the go-to language of the suckless community as well as most true experts, for example the Linux and OpenBSD developers, because of its good, relatively simple design, uncontested performance, wide support, great number of compilers, level of control and a greatly established and tested status. C is perhaps the most important language in history; it influenced, to smaller or greater degree, basically all of the widely used languages today such as C++, Java, JavaScript etc., however it is not a thing of the past -- in the area of low level programming C is still the number one unsurpassed language. C is by no means perfect but it is currently probably the best choice of a programming language (along with comun, of course). Though C is almost always compiled, there have appeared some C interpreters as well.

{ See https://wiki.bibanon.org/The_Perpetual_Playthings. Also look up The Ten Commandments for C Programmers by Henry Spencer. Also the Write in C song (parody of Let it Be). ~drummyfish }

It is usually not considered an easy language to learn because of its low level nature: it requires good understanding of how a computer actually works and doesn't prevent the programmer from shooting himself in the foot. Programmer is given full control (and therefore responsibility). There are things considered "tricky" which one must be aware of, such as undefined behavior of certain operators and raw pointers. This is what can discourage a lot of modern "coding monkeys" from choosing C, but it's also what inevitably allows such great performance -- undefined behavior allows the compiler to choose the most efficient implementation. On the other hand, C as a language is pretty simple without modern bullshit concepts such as OOP, it is not as much hard to learn but rather hard to master, as any other true art. In any case you have to learn C even if you don't plan to program in it regularly, it's the most important language in history and lingua franca of programming, you will meet C in many places and have to at least understand it: programmers very often use C instead of pseudocode to explain algorithms, C is used for optimizing critical parts even in non-C projects, many languages compile to C, it is just all around and you have to understand it like you have to understand English.

Some of the typical traits of C include great reliance on and utilization of preprocessor (macros, the underlying C code is infamously littered with "#ifdefs" all over the place which modify the code just before compiling -- this is mostly used for compile-time configuration and/or achieving better performance and/or for portability), pointers (direct access to memory, used e.g. for memory allocation, this is infamously related to "shooting oneself in the foot", e.g. by getting memory leaks) and a lot of undefined behavior (many things are purposefully left undefined in C to allow compilers to generate greatly efficient code, but this sometimes lead to weird bugs or a program working on one machine but not another, so C requires some knowledge of its specification). You can also infamously meet complicated type declarations like void (*float(int,void (*n)(int)))(int), these are frequently a subject of jokes ("look, C is simple").

Unlike many "modern" languages, C by itself doesn't offer too much advanced functionality such as displaying graphics, working with network, getting keyboard state and so on -- the base language doesn't even have any input/output, it's a pure processor of values in memory. The standard library offers things like basic I/O with standard input/output streams, basic operations with files, strings, time, math functions and other things, but for anything more advanced you will need an external library like SDL or Posix libraries.

C is said to be a "portable assembly" because of its low level nature, great performance etc. -- though C is structured (has control structures such as branches and loops) and can be used in a relatively high level manner, it is also possible to write assembly-like code that operates directly with bytes in memory through pointers without many safety mechanisms, so C is often used for writing things like hardware drivers. On the other hand some restrain from likening C to assembly because C compilers still perform many transformations of the code and what you write is not necessarily always what you get.

Mainstream consensus acknowledges that C is among the best languages for writing low level code and code that requires performance, such as operating systems, drivers or games. Even scientific libraries with normie-language interfaces -- e.g. various machine learning Python libraries -- usually have the performance critical core written in C. Normies will tell you that for things outside this scope C is not a good language, with which we disagree -- we recommend using C for basically everything that's supposed to last, i.e. if you want to write a good website, you should write it in C etc.

Is C low or high level? This depends on the context. Firstly back in the day when most computers were programmed in assembly, C was seen as high level, simply because it offered the highest level of abstraction at the time, while nowadays with languages like Python and JavaScript around people see C as very low level by comparison -- so it really depends on if you talk about C in context of "old" or "modern" programming and which languages you compare it to. Secondly it also depends on HOW you program in C -- you may choose to imitate assembly programming in C a lot, avoid using libraries, touch hardware directly, avoid using complex features and creating your own abstractions -- here you are really doing low level programming. On the other hand you can emulate the "modern" high-level style programming in C too, you can even mimic OOP and make it kind of "C++ with different syntax", you may use libraries that allow you to easily work with strings, heavy macros that pimp the language to some spectacular abomination, you may write your own garbage collector etc. -- here you are basically doing high level programming in C.

Fun: main[-1u]={1}; is a C compiler bomb :) it's a short program that usually makes the compiler produce a huge binary.

History and Context

C was developed in 1972 at Bell Labs alongside the Unix operating system by Dennis Ritchie and Brian Kerninghan, as a successor to the B language (portable language with recursion) written by Denis Ritchie and Ken Thompson, which was in turn inspired by the the ALGOL language (code blocks, lexical scope, ...). C was for a while called NB for "new B". C was intimately interconnected with Unix and its hacker culture, both projects would continue to be developed together, influencing each other. In 1973 Unix was rewritten in C. In 1978 Keninghan and Ritchie published a book called The C Programming Language, known as K&R, which became something akin the C specification. In March 1987 Richard Stallman along with others released the first version of GNU C compiler -- the official compiler of the GNU project and the compiler that would go on to become one of the most widely used. In 1989, the ANSI C standard, also known as C89, was released by the American ANSI -- this is a very well supported and overall good standard. The same standard was also adopted a year later by the international ISO, so C90 refers to the same language. In 1999 ISO issues a new standard that's known as C99, still a very good standard embraced by LRS. Later in 2011 and 2017 the standard was revised again to C11 and C17, which are however no longer considered good.

Standards

C is not a single language, there have been a few standards over the years since its inception in 1970s. The standard defines two major parts: the base language and standard library. Notable standards and versions are:

Quite nice online reference to all the different standards (including C++) is available at https://en.cppreference.com/w/c/99.

LRS should use C99 or C89 as the newer versions are considered bloat and don't have such great support in compilers, making them less portable and therefore less free.

The standards of C99 and older are considered pretty future-proof and using them will help your program be future-proof as well. This is to a high degree due to C having been established and tested better than any other language; it is one of the oldest languages and a majority of the most essential software is written in C, C compiler is one of the very first things a new hardware platform needs to implement, so C compilers will always be around, at least for historical reasons. C has also been very well designed in a relatively minimal fashion, before the advent of modern feature-creep and and bullshit such as OOP which cripples almost all "modern" languages.

Compilers

C is extreme well established, standardized and implemented so there is a great number of C compilers around. Let us list only some of the more notable ones.

Standard Library

Besides the pure C language the C standard specifies a set of libraries that have to come with a standard-compliant C implementation -- so called standard library. This includes e.g. the stdio library for performing standard input/output (reading/writing to/from screen/files) or the math library for mathematical functions. It is usually relatively okay to use these libraries as they are required by the standard to exist so the dependency they create is not as dangerous, however many C implementations aren't completely compliant with the standard and may come without the standard library. Also many stdlib implementations suck or you just can't be sure what the implementation will prefer (size? speed?) etc. So for sake of portability it is best if you can avoid using standard library.

The standard library (libc) is a subject of live debate because while its interface and behavior are given by the C standard, its implementation is a matter of each compiler; since the standard library is so commonly used, we should take great care in assuring it's extremely well written, however we ALWAYS have to choose our priorities and make tradeoffs, there just mathematically CANNOT be an ultimate implementation that will be all extremely fast and extremely memory efficient and extremely portable and extremely small. So choosing your C environment usually comprises of choosing the C compiler and the stdlib implementation. As you probably guessed, the popular implementations (glibc et al) are bloat and also often just shit. Better alternatives thankfully exist, such as:

Good And Bad Things About C

Firstly let's sum up some of the reasons why C is so good:

Now let's admit that nothing is perfect, not even C; it was one of the first relatively higher level languages and even though it has showed to have been designed extremely well, some things didn't age great, or were simply bad from the start. We still prefer this language as usually the best choice, but it's good to be aware of its downsides or smaller issues, if only for the sake of one day designing a better language. Please bear in mind all here are just suggestions, they made of course be a subject to counter arguments and further discussion. Here are some of the bad things about the language:

Basics

This is a quick overview, for a more in depth tutorial see C tutorial.

A simple program in C that writes "welcome to C" looks like this:

#include <stdio.h> // standard I/O library

int main(void)
{
  // this is the main program    

  puts("welcome to C");

  return 0; // end with success
}

You can simply paste this code into a file which you name e.g. program.c, then you can compile the program from command line like this:

gcc -o program program.c

Then if you run the program from command line (./program on Unix like systems) you should see the message.

Cheatsheet/Overview

Here is a quick reference cheatsheet of some of the important things in C, also a possible overview of the language.

data types (just some):

data type values (size) printf notes
int (signed int, ...) integer, at least -32767 to 32767 (16 bit), often more %d native integer, fast (prefer for speed)
unsigned int integer, non-negative, at least 0 to 65535, often more %u same as int but no negative values
signed char integer, at least -127 to 127, mostly -128 to 127 %c, %hhi char forced to be signed
unsigned char integer, at least 0 to 255 (almost always the case) %c, %hhu smallest memory chunk, byte
char integer, at least 256 values %c signed or unsigned, used for string characters
short integer, at least -32767 to 32767 (16 bit) %hd like int but supposed to be smaller
unsigned short integer, non-negative, at least 0 to 65535 %hu like short but unsigned
long integer, at least -2147483647 to 2147483647 (32 bit) %ld for big signed values
unsigned long integer, at least 0 to 4294967295 (32 bit) %lu for big unsigned values
long long integer, at least some -9 * 10^18 to 9 * 10^18 (64 bit) %lld for very big signed values
unsigned long long integer, at least 0 to 18446744073709551615 (64 bit) %llu for very big unsigned values
float floating point, some -3 * 10^38 to 3 * 10^38 %f float, tricky, bloat, can be slow, avoid
double floating point, some -1 * 10^308 to 10^308 %lf like float but bigger
T [N] array of N values of type T array, if T is char then string
T * memory address %p pointer to type T, (if char then string)
uint8_t 0 to 255 (8 bit) PRIu8 exact width, two's compl., must include <stdint.h>
int8_t -128 to 127 (8 bit) PRId8 like uint8_t but signed
uint16_t 0 to 65535 (16 bit) PRIu16 like uint8_t but 16 bit
int16_t -32768 to 32767 (16 bit) PRId16 like uint16_t but signed
uint32_t -2147483648 to 2147483647 (32 bit) PRIu32 like uint8_t but 32 bit
int32_t 0 to 4294967295 (32 bit) PRId32 like uint32_t but signed
int_least8_t at least -128 to 127 PRIdLEAST8 signed integer with at least 8 bits, <stdint.h>
int_fast8_t at least -128 to 127 PRIdFAST8 fast signed int. with at least 8 bits, <stdint.h>
struct structured data type

There is no bool (true, false), use any integer type, 0 is false, everything else is true (there may be some bool type in the stdlib, don't use that). A string is just array of chars, it has to end with value 0 (NOT ASCII character for "0" but literally integer value 0)!

main program structure:

#include <stdio.h>

int main(void)
{
  // code here
  return 0;
}

branching aka if-then-else:

if (CONDITION)
{
  // do something here
}
else // optional
{
  // do something else here
}

for loop (repeat given number of times):

for (int i = 0; i < MAX; ++i)
{
  // do something here, you can use i
}

while loop (repeat while CONDITION holds):

while (CONDITION)
{
  // do something here
}

do while loop (same as while but CONDITION at the end), not used that much:

do
{
  // do something here
} while (CONDITION);

function definition:

RETURN_TYPE myFunction (TYPE1 param1, TYPE2 param2, ...)
{ // return type can be void
  // do something here
}

compilation (you can replace gcc with another compiler):

To link a library use -llibrary, e.g. -lm (when using <math.h>), -lSDL2 etc.

The following are some symbols (functions, macros, ...) from the standard library:

symbol library description example
putchar(c) stdio.h Writes a single character to output. putchar('a');
getchar() stdio.h Reads a single character from input. int inputChar = getchar();
puts(s) stdio.h Writes string to output (adds newline at the end). puts("hello");
printf(s, a, b, ...) stdio.h Complex print func., allow printing numbers, their formatting etc. printf("value is %d\n",var);
scanf(s, a, b, ...) stdio.h Complex reading func., allows reading numbers etc. scanf("%d",&var);
fopen(f,mode) stdio.h Opens file with given name in specific mode, returns pointer. FILE *myFile = fopen("myfile.txt","r");
fclose(f) stdio.h Closes previously opened file. fclose(myFile);
fputc(c,f) stdio.h Writes a single character to file. fputc('a',myFile);
fgetc(f) stdio.h Reads a single character from file. int fileChar = fgetc(myFile);
fputs(s,f) stdio.h Writes string to file (without newline at end). fputs("hello",myFile);
fprintf(s, a, b, ...) stdio.h Like printf but outputs to a file. fprintf(myFile,"value is %d\n",var);
fscanf(f, s, a, b, ...) stdio.h Like scanf but reads from a file. fscanf(myFile,"%d",&var);
fread(data,size,n,f) stdio.h Reads n elems to data from file, returns no. of elems read. fread(myArray,sizeof(item),1,myFile);
fwrite(data,size,n,f) stdio.h Writes n elems from data to file, returns no. of elems writ. fwrite(myArray,sizeof(item),1,myFile);
EOF stdio.h End of file value. int c = getchar(); if (c == EOF) break;
rand() stdlib.h Returns pseudorandom number. char randomLetter = 'a' + rand() % 26;
srand(n) stdlib.h Seeds pseudorandom number generator. srand(time(NULL));
NULL stdlib.h, ... Value assigned to pointers that point "nowhere". int *myPointer = NULL;
malloc(size) stdlib.h Dynamically allocates memory, returns pointer to it (or NULL). int *myArr = malloc(sizeof(int) * 10);
realloc(mem,size) stdlib.h Resizes dynamically allocates memory, returns pointer (or NULL). myArr = realloc(myArr,sizeof(int) * 20);
free(mem) stdlib.h Frees dynamically allocated memory. free(myArr);
atof(str) stdlib.h Converts string to floating point number. double val = atof(answerStr);
atoi(str) stdlib.h Converts string to integer number. int val = atof(answerStr);
EXIT_SUCCESS stdlib.h Value the program should return on successful exit. return EXIT_SUCCESS;
EXIT_FAILURE stdlib.h Value the program should return on exit with error. return EXIT_FAILURE;
sin(x) math.h Returns sine of angle in RADIANS. float angleSin = sin(angle);
cos(x) math.h Like sin but returns cosine. float angleCos = cos(angle);
tan(x) math.h Returns tangent of angle in RADIANS. float angleTan = tan(angle);
asin(x) math.h Returns arcus sine of angle, in RADIANS. float angle = asin(angleSine);
ceil(x) math.h Rounds a floating point value up. double x = ceil(y);
floor(x) math.h Rounds a floating point value down. double x = floor(y);
fmod(a,b) math.h Returns floating point reminded after division. double rem = modf(x,3.5);
isnan(x) math.h Checks if given float value is NaN. if (!isnan(x))
NAN math.h Float quiet NaN (not a number) value, don't compare! if (y == 0) return NAN;
log(x) math.h Computes natural logarithm (base e). double x = log(y);
log10(x) math.h Computes decadic logarithm (base 10). double x = log10(y);
log2(x) math.h Computes binary logarithm (base 2). double x = log2(y);
exp(x) math.h Computes exponential function (e^x). double x = exp(y);
sqrt(x) math.h Computes floating point square root. double dist = sqrt(dx * dx + dy * dy);
pow(a,b) math.h Power, raises a to b (both floating point). double cubeRoot = pow(var,1.0/3.0);
abs(x) math.h Computes absolute value. double varAbs = abs(var);
INT_MAX limits.h Maximum value that can be stored in int type. printf("int max: %d\n",INT_MAX);
memset(mem,val,size) string.h Fills block of memory with given values. memset(myArr,0,sizeof(myArr));
memcpy(dest,src,size) string.h Copies bytes of memory from one place to another, returns dest. memcpy(destArr,srcArr,sizeof(srcArr);
strcpy(dest,src) string.h Copies string (zero terminated) to dest, unsafe. char myStr[16]; strcpy(myStr,"hello");
strncpy(dest,src,n) string.h Like strcpy but limits max number of bytes to copy, safer. strncpy(destStr,srcStr,sizeof(destStr));
strcmp(s1,s2) string.h Compares two strings, returns 0 if equal. if (!strcmp(str1,"something"))
strlen(str) string.h Returns length of given string. int l = strlen(myStr);
strstr(str,substr) string.h Finds substring in string, returns pointer to it (or NULL). if (strstr(cmdStr,"quit") != NULL)
time(t) time.h Stores calendar time (often Unix t.) in t (can be NULL), returns it. printf("tstamp: %d\n",(int) time(NULL));
clock() time.h Returns approx. CPU cycle count since program start. printf("CPU ticks: %d\n",(int) clock());
CLOCKS_PER_SEC time.h Number of CPU ticks per second. int sElapsed = clock() / CLOCKS_PER_SEC;

Some Programs In C

TODO

See Also


Powered by nothing. All content available under CC0 1.0 (public domain). Send comments and corrections to drummyfish at disroot dot org.