2024-03-29.
A brief reference for the differences between C standards. Source#K&R_C)
Anything before standardisation was called K&R C as per the first edition of the book that was the de facto implementation at the time. The book came out at 1978, so sometimes this implementation is also referred to as C78.
The following language features were introduced by the book:
long int data type.unsigned int data type.a =+ 1; has become a += 1;. This happened to remove ambiguity. Before, a=-10; meant a =- 10; instead of a = -10;C functions that returned an int could be declared without the int keyword upfront as it was implicit that they returned int.
/* K&R */
long function_that_returns_long();
function_that_returns_int();
/* newer standards */
long function_that_returns_long();
int function_that_returns_int();
Function declarations also had an implicit int return when the return type was not specified:
/* K&R */
function_that_returns_int() {
return 10;
}
/* newer standards */
int function_that_returns_int() {
return 10;
}
Function declarations also didn't include information about function arguments. This means that function parameter type checks were not performed. Some compilers would still raise a warning if the function was called with the wrong number of arguments or if different calls to the same function had different numbers of arguments.
After the book publication and before C89, several compilers added other features to the language:
void functions.struct and union types. Prior to that only a pointer (int or float) could be returned.struct data types.enum types. Before that, preprocessors were used like #define BLUE 0.The goal of this standards was to create a superset of K&R out of the many unofficial features, such as:
/* before (no argument info in declarations) */
long function_that_returns_long();
/* C89 */
long function_that_returns_long(int a, int b);
void pointers.const qualifier.#error and #pragma directives.The following functionalities were introduced in this new version of the standard:
inline functions. Those are used to suggest (but not mandate) the compiler to inline the body of the function where it is called by performing inline expansion.inline void swap(int *m, int* n) {
int tmp = *m;
*m = *n;
*n = tmp;
}
struct point p = { .x = 1, .y = 2 };
my_sweet_function_call((struct x) {1, 2});
long long int and complex.float read_and_process(int n)
{
float vals[n];
for (int i = 0; i < n; ++i)
vals[i] = read_val();
return process(n, vals);
}
static in array indices in parameter declarations was added. The below indicates that the array size is determined by the params rows and cols:void function(int rows, int cols, int array[static rows][cols]) {
// Function implementation
}
struct vectord {
short len; // there must be at least one other data member
double arr[]; // the flexible array member must be last.
// The compiler may reserve extra padding space here, like it can between struct members
};
//.\u0040 .restrict qualification allows more aggressive code optimization, removing compile-time array access advantages previously held by FORTRAN over ANSI C. This is used to tell the compiler two pointers don't point to the same address in memory. With that, the compiler can aggressively optimise the code as it knows pointers won't be aliased (overlapped in memory).void update(int *restrict a, int *restrict b, int n) {
// Using 'restrict' keyword to indicate no aliasing
for (int i = 0; i < n; i++) {
a[i] += b[i];
}
}
_Noreturn this specifier informs the compiler that once the function is called, it will never return control to the calling function. The _Noreturn keyword for compilers that don't support the C11 standard but still want to use this feature._Alignas specifier, _Alignof operator, aligned_alloc function, // Align the array to a 16-byte boundary.
_Alignas(16) char aligned_array[32];
// Get the alignment requirement of a data type.
printf("Alignment of int: %zu\n", _Alignof(int));
// Allocate 32 bytes of memory aligned to a 16-byte boundary
void *ptr = aligned_alloc(16, 32);
// header provides similar functionality:
alignas(16) char aligned_array[32];
printf("Alignment of aligned_array: %zu\n", alignof(aligned_array));
_Generic keyword.#define print_value(x) _Generic((x), \
int: printf("%d\n", x), \
float: printf("%f\n", x), \
double: printf("%lf\n", x), \
default: printf("Unsupported type\n") \
)
_Thread_local storage-class specifier and memcpy_s , memmove_s, strcpy_s, strncpy_s, and others with the _s suffix, which perform bounds-checking for array accesses. These functions typically take additional parameters specifying the size of the destination buffer to ensure that the copy operation does not exceed the buffer size. These changes remain controversial and they haven't been widely implemented._Static_assert keyword, allowing programmers to embed compile-time assertions directly into their code. There is also the library static_assert .struct T { int tag; union { float x; int n; }; };
quick_exit function as a third way to terminate a program, intended to do at least minimal deinitialisation.real + imaginary*I might not yield the expected value if imaginary is infinite or NaN).C17 fixes numerous minor defects in C11 without introducing new language features.
Embedded C is a set of language extensions for the C programming language by
the C Standards Committee to address commonality issues that exist between C
extensions for different embedded systems.
These include:
M Maannyy eemmbbeeddddeedd pprroocceessssoorrss llaacckk aann FFPPUU,, bbeeccaauussee iinntteeggeerr aarriitthhmmeettiicc uunniittss
rreeqquuiirree ssuubbssttaannttiiaallllyy ffeewweerr llooggiicc ggaatteess aanndd ccoonnssuummee mmuucchh ssmmaalllleerr cchhiipp aarreeaa
tthhaann aann FFPPUU