diff --git a/clang.md b/clang.md index 64740369704e795ef344df381c9f9788fb3c3a1f..92d5dd3b9cfbbf3dfafac7ea4dd9f8758d3f03f2 100644 --- a/clang.md +++ b/clang.md @@ -8,7 +8,7 @@ We will focus on common errors, caveats and important concepts that might ease y C only guarantees minimum and relative size of "int", "short" etc... The range that each type can represent depends on the implementation. -The integer data types range in size from at least 8 bits to at least 32 bits. The C99 standard extends this range to include integer sizes of at least 64 bits. +The integer data types range in size from at least 8 bits to at least 32 bits. The C99 standard extends this range to include integer sizes of at least 64 bits. The types are ordered by the width, guaranteeing that _wider_ types are at least as large as _narrower_ types. E.g. `long long int` can represents all values that a `long int` can represent. @@ -87,7 +87,7 @@ int foo(int* p) else return 0; } - + int bar() { int* p = NULL; @@ -158,7 +158,7 @@ int main() { return EXIT_FAILURE; } free(buf); - strcpy(buf, ftr); // UB + strcpy(buf, ftr); // UB printf("buf = %s\n", buf); return EXIT_SUCCESS; @@ -241,7 +241,7 @@ void foo(void *v) { ### Void Pointer -We should also know that void pointers can be **casted** into any type of pointer. +We should also know that void pointers can be **casted** into any type of pointer. In C, library functions like `malloc`, `calloc` etc. return void pointers, which we can then cast in to any other type of pointers as we need: @@ -296,8 +296,8 @@ Arrays in C are very primitive: - An Array in C does not have the information to its own length, not like `arr.length` in other languages - Array's bounds are not checked at all - - So we can easily access off the end of an array - - We muss pass the array and its size together to any function that is going to manipulate it + - So we can easily access off the end of an array + - We muss pass the array and its size together to any function that is going to manipulate it ## Strings @@ -357,31 +357,30 @@ Objects declared in file scope have `static` storage duration. The lifetime of t #### Allocated -`Allocated` storage is allocated and deallocated through library functions on requests, using dynamic memory allocation functions. - +`Allocated` storage is allocated and deallocated through library functions on requests, using dynamic memory allocation functions. A concrete example of these storage durations: ```c #include <stdio.h> #include <stdlib.h> - + /* static storage duration */ int A; - + int main(void) { printf("&A = %p\n", (void*)&A); - + /* automatic storage duration */ int A = 1; // hides global A printf("&A = %p\n", (void*)&A); - + /* allocated storage duration */ int *ptr_1 = malloc(sizeof(int)); /* start allocated storage duration */ printf("address of int in allocated memory = %p\n", (void*)ptr_1); free(ptr_1); /* stop allocated storage duration */ -} +} ``` ### Dynamic Memory Allocation @@ -557,3 +556,82 @@ Using the header guard prevents the function definition of `func` being included A common practice when picking the identifier to use as a header file guard is to use the salient parts of the file path, filename, and extension, separated by an underscore and written in all capital letters. E.g. `FOO_BAR_BAZ_H` for a file located in `foo/bar/baz.h`. There are other ways of using the preprocessor directives and macros, this [article](https://en.wikibooks.org/wiki/C_Programming/Preprocessor_directives_and_macros) and [GCC documentation](https://gcc.gnu.org/onlinedocs/cpp/) provide extensive information about them. + +## C Program Structure + +We've talked about storage duration above. Storage duration and linkage are closely related. In C, you can use the **storage-class specifiers** to specify the storage duration and linkage of an object or a function, they are: + +- `auto`: automatic duration and no linkage +- `register`: automatic duration and no linkage; address of this variable cannot be taken (we won't cover this, it's quite rare ) +- `static`: static duration and internal linkage +- `extern`: static duration and external linkage + +### Linkage + +Linkage refers to the ability of an **identifier (variable or function)** to be referred to in other scopes. + +C provides three kinds of linkage: + +- `none`: The identifier can be referred to only from the scope it is in. +- `external`: The identifier can be referred to from everywhere in the program. (E.g. from other source file). +- `internal`: The identifier can only be referred to within the translation unit that contains the declaration. + +There are some implicit rules if no storage-class specifier is provided, the defaults are: + +- `extern` for all functions +- `extern` for all objects at file scope +- `auto` for objects at block scope + +Let's look at some examples. + +```c +// flib.h +#ifndef FLIB_H +#define FLIB_H + void f(void); // function declaration with external linkage + extern int state; // variable declaration with external linkage + static const int size = 5; // definition of a read-only variable with internal linkage + enum { MAX = 10 }; // constant definition +#endif // FLIB_H +``` + +```c +// flib.c +#include "flib.h" +static void local_f(int s) {} // definition with internal linkage (only used in this file) +static int local_state; // definition with internal linkage (only used in this file) + +int state; // definition with external linkage (used by main.c) +void f(void) { local_f(state); } // definition with external linkage (used by main.c) +``` + +```c +// main.c +#include "flib.h" +int main(void) +{ + int x[MAX] = {size}; // uses the constant and the read-only variable + state = 7; // modifies state in flib.c + f(); // calls f() in flib.c +} +``` + +#### Special Use of `static` + +Declaring a variable at block scope as static creates an identifier with no linkage, but it does give the variable static storage duration: + +```c +#include <stdio.h> + +void foo() { + static int count = 0; // count has no linkage but has static storage duration + printf("Function has been called %d times\n", ++count); +} + +int main() { + foo(); + foo(); + foo(); + return 0; +} +```