mirror of
https://github.com/libretro/cpp-cheat.git
synced 2025-02-17 06:42:27 +00:00
Improve index
This commit is contained in:
parent
987b26f008
commit
b5b81f0d99
@ -1,2 +1,2 @@
|
||||
# Cannoe be a symlink.
|
||||
# Cannot be a symlink.
|
||||
language: cpp
|
||||
|
39
CONTRIBUTING.md
Normal file
39
CONTRIBUTING.md
Normal file
@ -0,0 +1,39 @@
|
||||
# CONTRIBUTING
|
||||
|
||||
## Style
|
||||
|
||||
Non-portable features shall be clearly separated from portable ones in either:
|
||||
|
||||
- ifdef macro blocks
|
||||
- separate files
|
||||
- separate directories
|
||||
- separate repositories
|
||||
|
||||
This includes features which were not present in the first standardized version of languages. E.g., C99 features must be put inside `#ifdf __STDC_VERSION__` blocks.
|
||||
|
||||
Everything that can be checked in an assertion will be checked, and will not get printed.
|
||||
|
||||
For example, a C addition operator `+` test should be done as:
|
||||
|
||||
assert(1 + 1 == 2);
|
||||
|
||||
and *never*:
|
||||
|
||||
printf("%d\n", 1 + 1);
|
||||
|
||||
so that all can be verified automatically.
|
||||
|
||||
Features which yield unpredictable outputs can print results to stdout. For example, `time(NULL)`
|
||||
|
||||
printf("%d\n", 1 + 1);
|
||||
|
||||
Features that:
|
||||
|
||||
- require user input such as C `scanf`
|
||||
- make programs wait for perceptible amounts of time
|
||||
|
||||
shall be put inside a block analogous to a `if (0){ ... }` to be turned on only when users want to test those specific features.
|
||||
|
||||
Cheat source comments are written in markdown *indented by headers* and commented out.
|
||||
|
||||
Every important keyword that one might search for in the feature has a hash before it, e.g. `#function`, `#include`, `#printf`, etc.
|
142
README.md
142
README.md
@ -6,113 +6,35 @@ C and C++ information, cheatsheets and mini-projects.
|
||||
|
||||
Relies on <https://github.com/cirosantilli/cpp-boilerplate> to factor code out. See [its documentation](https://github.com/cirosantilli/cpp-boilerplate/blob/master/README.md) for information on how to use this project.
|
||||
|
||||
## Most useful files
|
||||
|
||||
- [c.c](c.c): C cheatsheet
|
||||
- [cpp.cpp](main_cpp.cpp): C++ cheatsheet
|
||||
- [POSIX](posix/): POSIX C API
|
||||
- [Multi-file](multifile/): `include`, `extern` vs `static`, dynamic libraries, cross language calls
|
||||
- [GCC](gcc/): GCC extensions
|
||||
- [OpenGL](opengl/)
|
||||
- [KDE](kde/)
|
||||
|
||||
Other files:
|
||||
|
||||
- [Boost](boost/)
|
||||
- [Flex and Bison](flex-bison/)
|
||||
- [GDB](gdb.md)
|
||||
- [glibc](glibc/)
|
||||
- [Implementations](implementations.md)
|
||||
- [Style guides](style-guides.md)
|
||||
- [CMake](cmake.md)
|
||||
- [hello_world.c](hello_world.c)
|
||||
- [hello_world_cpp.cpp](hello_world_cpp.cpp)
|
||||
|
||||
GUI:
|
||||
|
||||
- [GTK](gtk/)
|
||||
- [Qt](qt/)
|
||||
- [X11](x11)
|
||||
- [Open GL](opengl/)
|
||||
|
||||
Scientific:
|
||||
|
||||
- [Fortran](fortran/)
|
||||
- [GSL](gsl/)
|
||||
- [LAPACK](lapack/)
|
||||
- [OpenCV](opencv/)
|
||||
- [PLplot](plplot/)
|
||||
|
||||
## Dependencies
|
||||
|
||||
Most builds require:
|
||||
|
||||
- `make` (POSIX)
|
||||
- `gcc` >= 4.7
|
||||
- `g++` >= 4.7
|
||||
|
||||
Even though we use GNU tools by default, great attention is paid to portability of portable subjects like ANSI C, which should compile in any compiler.
|
||||
|
||||
In addition, each directory may have their own extra dependencies as stated in their README.
|
||||
|
||||
You can install dependencies on latest LTS Ubuntus with:
|
||||
|
||||
./configure
|
||||
|
||||
Other system install are not going to be supported as that would lead to too much maintenance overhead. If you don't have Ubuntu, consider using our [Vagrantfile](Vagrantfile).
|
||||
|
||||
## Usage
|
||||
|
||||
When there are multiple files compiled, e.g.:
|
||||
|
||||
c.c -> c
|
||||
cpp.cpp -> cpp
|
||||
|
||||
run a given file by specifying the basename without extension:
|
||||
|
||||
make run=c
|
||||
make run=cpp
|
||||
|
||||
The `=` sign is *not* optional!
|
||||
|
||||
Doing just `make run` in those cases will run the default file: `main`.
|
||||
|
||||
## Style
|
||||
|
||||
Non-portable features shall be clearly separated from portable ones in either:
|
||||
|
||||
- ifdef macro blocks
|
||||
- separate files
|
||||
- separate directories
|
||||
- separate repositories
|
||||
|
||||
This includes features which were not present in the first standardized version of languages. E.g., C99 features must be put inside `#ifdf __STDC_VERSION__` blocks.
|
||||
|
||||
Everything that can be checked in an assertion will be checked, and will not get printed.
|
||||
|
||||
For example, a C addition operator `+` test should be done as:
|
||||
|
||||
assert(1 + 1 == 2);
|
||||
|
||||
and *never*:
|
||||
|
||||
printf("%d\n", 1 + 1);
|
||||
|
||||
so that all can be verified automatically.
|
||||
|
||||
Features which yield unpredictable outputs can print results to stdout. For example, `time(NULL)`
|
||||
|
||||
printf("%d\n", 1 + 1);
|
||||
|
||||
Features that:
|
||||
|
||||
- require user input such as C `scanf`
|
||||
- make programs wait for perceptible amounts of time
|
||||
|
||||
shall be put inside a block analogous to a `if (0){ ... }` to be turned on only when users want to test those specific features.
|
||||
|
||||
Cheat source comments are written in markdown *indented by headers* and commented out.
|
||||
|
||||
Every important keyword that one might search for in the feature has a hash before it, e.g. `#function`, `#include`, `#printf`, etc.
|
||||
|
||||
##
|
||||
1. [Getting started](getting-started.md)
|
||||
1. Best content
|
||||
1. [c.c](c.c): C cheatsheet
|
||||
1. [cpp.cpp](main_cpp.cpp): C++ cheatsheet
|
||||
1. [POSIX](posix/): POSIX C API
|
||||
1. [Multi-file](multifile/): `include`, `extern` vs `static`, dynamic libraries, cross language calls
|
||||
1. [GCC](gcc/): GCC extensions
|
||||
1. [OpenGL](opengl/)
|
||||
1. [KDE](kde/)
|
||||
1. Other files
|
||||
1. [Boost](boost/)
|
||||
1. [Flex and Bison](flex-bison/)
|
||||
1. [GDB](gdb.md)
|
||||
1. [glibc](glibc/)
|
||||
1. [Implementations](implementations.md)
|
||||
1. [Style guides](style-guides.md)
|
||||
1. [CMake](cmake.md)
|
||||
1. [hello_world.c](hello_world.c)
|
||||
1. [hello_world_cpp.cpp](hello_world_cpp.cpp)
|
||||
1. GUI
|
||||
1. [GTK](gtk/)
|
||||
1. [Qt](qt/)
|
||||
1. [X11](x11)
|
||||
1. [Open GL](opengl/)
|
||||
1. Scientific
|
||||
1. [Fortran](fortran/)
|
||||
1. [GSL](gsl/)
|
||||
1. [LAPACK](lapack/)
|
||||
1. [OpenCV](opencv/)
|
||||
1. [PLplot](plplot/)
|
||||
1. [CONTRIBUTING](CONTRIBUTING.md)
|
||||
1. [Bibliography](bibliography.md)
|
||||
|
59
bibliography.md
Normal file
59
bibliography.md
Normal file
@ -0,0 +1,59 @@
|
||||
# Bibliography
|
||||
|
||||
## Free
|
||||
|
||||
- <http://www.cplusplus.com>
|
||||
|
||||
Explains well what most the features of the language do for beginners.
|
||||
|
||||
Not official in any way, despite the amazing URL and Google rank.
|
||||
|
||||
Is said to contain many errors, and that `cppreference` is superior.
|
||||
|
||||
- <http://en.cppreference.com/w/>
|
||||
|
||||
Similar to `cplusplus.com`, but seems to have more info.
|
||||
|
||||
Wiki driven.
|
||||
|
||||
Attempts to document all the language and stdlibs.
|
||||
|
||||
Many behaviour examples.
|
||||
|
||||
- <http://www.parashift.com/c++-faq/index.html>
|
||||
|
||||
C++ FAQ.
|
||||
|
||||
Deep and extensive tutorial.
|
||||
|
||||
- <http://herbsutter.com/gotw/>
|
||||
|
||||
Herb Sutter Guru of the week.
|
||||
|
||||
Hard topics with simple examples.
|
||||
|
||||
- <http://yosefk.com/c++fqa/>
|
||||
|
||||
Comments on the quirks of c++.
|
||||
|
||||
Fun and informative for those that know the language at intermediate level.
|
||||
|
||||
- <http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp>
|
||||
|
||||
IBM implementation of C++.
|
||||
|
||||
Contains a few extension, but lots of well explained docs with many examples.
|
||||
|
||||
Contains clear examples and explanations on very specific subjects.
|
||||
|
||||
Horrible navigation and URLs.
|
||||
|
||||
- <http://www.agner.org/optimize/>
|
||||
|
||||
Hardcore optimization tutorials for C++ and assembly.
|
||||
|
||||
## Non-free
|
||||
|
||||
- <http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list>
|
||||
|
||||
List of books.
|
444
c.c
444
c.c
@ -203,21 +203,15 @@ Small comments on comparing ANSI C with extensions are acceptable.
|
||||
*/
|
||||
|
||||
/*
|
||||
# Preprocessor
|
||||
# include
|
||||
|
||||
Loes simple stuff *before* compilation.
|
||||
Look in standard dirs directly:
|
||||
|
||||
Ly simple understand non-turing complete.
|
||||
#include <file.h>
|
||||
|
||||
# include
|
||||
Looks in current dir first:
|
||||
|
||||
Look in standard dirs directly:
|
||||
|
||||
#include <file.h>
|
||||
|
||||
Looks in current dir first:
|
||||
|
||||
#include "file.h"
|
||||
#include "file.h"
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
@ -233,7 +227,7 @@ Small comments on comparing ANSI C with extensions are acceptable.
|
||||
#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 */
|
||||
#include <string.h> /* sprintf, strlen, strcpy, memset, memcmp */
|
||||
#include <math.h>
|
||||
#include <time.h> /* time() */
|
||||
|
||||
@ -476,8 +470,8 @@ int setjmp_func(int jmp, jmp_buf env_buf) {
|
||||
# overload
|
||||
|
||||
There is no function overloading in C to avoid name mangling:
|
||||
C ABI simplifity is one of it's greatest strengths:
|
||||
<http://stackoverflow.com/questions/8773992/c11-type-generic-expressions-why-not-just-add-function-overloading>
|
||||
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.
|
||||
*/
|
||||
@ -1556,11 +1550,13 @@ int main(int argc, char **argv) {
|
||||
|
||||
{ char c = (char)130; }
|
||||
|
||||
/* Possible via escape seqs like in strings. */
|
||||
/* Possible via escape sequences are like in strings. */
|
||||
|
||||
{ assert(((int)'\n') == 10); }
|
||||
assert(((int)'\n') == 0x0a);
|
||||
assert(((int)'\'') == 0x27);
|
||||
|
||||
/* TODO how to make a literal backslash char? */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1793,7 +1789,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
Language keyword.
|
||||
|
||||
Gives the size of the RAM representation of types in bytes.
|
||||
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.
|
||||
|
||||
@ -1823,11 +1820,11 @@ int main(int argc, char **argv) {
|
||||
|
||||
# Fixed size types
|
||||
|
||||
besides the base times with nonfixed sizes, c99 ANSI libc also furnishes
|
||||
fixed sized types. See
|
||||
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
|
||||
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.
|
||||
*/
|
||||
{
|
||||
@ -1835,33 +1832,37 @@ int main(int argc, char **argv) {
|
||||
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) );
|
||||
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 );
|
||||
|
||||
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 ));
|
||||
|
||||
/* size equality is always possible: */
|
||||
/*
|
||||
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);
|
||||
|
||||
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 ));
|
||||
|
||||
/* unsigned does not change sizeof: */
|
||||
|
||||
assert(sizeof(unsigned int) == sizeof(int));
|
||||
assert(sizeof(unsigned long int) == sizeof(long int));
|
||||
/* Unsigned does not change sizeof: */
|
||||
assert(sizeof(unsigned int) == sizeof(int));
|
||||
assert(sizeof(unsigned long int) == sizeof(long int));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3904,32 +3905,73 @@ int main(int argc, char **argv) {
|
||||
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 */
|
||||
/*
|
||||
# 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.
|
||||
*/
|
||||
{
|
||||
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);
|
||||
# Negation
|
||||
*/
|
||||
{
|
||||
assert((!0) == 1);
|
||||
assert((!1) == 0);
|
||||
assert((!2) == 0);
|
||||
assert((!-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);
|
||||
/*
|
||||
`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);
|
||||
@ -3958,20 +4000,28 @@ int main(int argc, char **argv) {
|
||||
|
||||
/* # Bitwise operators */
|
||||
{
|
||||
/* NOT */
|
||||
/*
|
||||
# ~
|
||||
|
||||
# NOT bitwise
|
||||
*/
|
||||
assert((~(char)0x00) == (char)0xFF);
|
||||
assert((~(char)0xFF) == (char)0x00);
|
||||
|
||||
/* AND bitwise */
|
||||
/*
|
||||
# &
|
||||
|
||||
AND bitwise
|
||||
*/
|
||||
{
|
||||
assert(((char)0x00 & (char)0x00) == (char)0x00);
|
||||
assert(((char)0xFF & (char)0x00) == (char)0x00);
|
||||
assert(((char)0xFF & (char)0xFF) == (char)0xFF);
|
||||
|
||||
/*
|
||||
# even
|
||||
# Even
|
||||
|
||||
# odd
|
||||
# Odd
|
||||
|
||||
# Find if number is even or odd
|
||||
|
||||
@ -3987,12 +4037,20 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
/* OR */
|
||||
/*
|
||||
# ||
|
||||
|
||||
# OR bitwise
|
||||
*/
|
||||
assert(((char)0x00 | (char)0x00) == (char)0x00);
|
||||
assert(((char)0xFF | (char)0x00) == (char)0xFF);
|
||||
assert(((char)0xFF | (char)0xFF) == (char)0xFF);
|
||||
|
||||
/* XOR */
|
||||
/*
|
||||
# ^
|
||||
|
||||
# XOR bitwise
|
||||
*/
|
||||
assert(((char)0x00 ^ (char)0x00) == (char)0x00);
|
||||
assert(((char)0xFF ^ (char)0x00) == (char)0xFF);
|
||||
assert(((char)0xFF ^ (char)0xFF) == (char)0x00);
|
||||
@ -5196,28 +5254,84 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
/* # String literals */
|
||||
/*
|
||||
# String literals
|
||||
|
||||
http://en.cppreference.com/w/c/language/string_literal
|
||||
*/
|
||||
{
|
||||
/* Escape chars in string conts */
|
||||
{
|
||||
puts("Backslash escapes:");
|
||||
puts(">>>\"<<< double quotes");
|
||||
puts(">>>\\<<< backslash");
|
||||
puts(">>>\n<<< new line");
|
||||
puts(">>>\t<<< tab char");
|
||||
puts(">>>\f<<< feed char");
|
||||
puts(">>>\v<<< vertical tab");
|
||||
puts(">>>\r<<< carriage return");
|
||||
puts(">>>\a<<< alert (your terminal may interpret this as a sound beep or not)");
|
||||
puts(">>>\x61<<< a in hexadecimal");
|
||||
/* 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. */
|
||||
/* 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');
|
||||
|
||||
/* \e is a notable GNU extension for the ESC character. */
|
||||
/* 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 */
|
||||
@ -6159,7 +6273,13 @@ int main(int argc, char **argv) {
|
||||
assert(getenv("NOT_DEFINED") == NULL);
|
||||
}
|
||||
|
||||
/* # preprocessor */
|
||||
/*
|
||||
# preprocessor
|
||||
|
||||
Does simple operations before compilation.
|
||||
|
||||
Not Turing complete.
|
||||
*/
|
||||
{
|
||||
/*
|
||||
# #define
|
||||
@ -6170,6 +6290,16 @@ int main(int argc, char **argv) {
|
||||
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
|
||||
@ -6337,7 +6467,11 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
/*
|
||||
# #if ##else
|
||||
# #if
|
||||
|
||||
# #else
|
||||
|
||||
# #elif
|
||||
|
||||
The preprocessor can do certain integer arithmetic operations such as: +, -, ==, <.
|
||||
*/
|
||||
@ -7011,39 +7145,33 @@ int main(int argc, char **argv) {
|
||||
TODO what happens when a wrong type is passed? Typecast? Undefined?
|
||||
*/
|
||||
{
|
||||
printf("u UINT_MAX = %u\n", UINT_MAX);
|
||||
printf("u UINT_MAX = %u\n", UINT_MAX);
|
||||
|
||||
sprintf(s, "%d", UINT_MAX);
|
||||
assert(strcmp(s, "-1") == 0);
|
||||
sprintf(s, "%d", UINT_MAX);
|
||||
assert(strcmp(s, "-1") == 0);
|
||||
}
|
||||
|
||||
/* char: */
|
||||
/* char */
|
||||
sprintf(s, "%c", 'a');
|
||||
assert(strcmp(s, "a") == 0);
|
||||
|
||||
sprintf(s, "%c", 'a');
|
||||
assert(strcmp(s, "a") == 0);
|
||||
|
||||
/* int: */
|
||||
|
||||
printf("d INT_MAX = %d\n", INT_MAX);
|
||||
/* int */
|
||||
printf("d INT_MAX = %d\n", INT_MAX);
|
||||
|
||||
/* long int: */
|
||||
|
||||
printf("d LONG_MAX = %ld\n", LONG_MAX);
|
||||
printf("d LONG_MAX = %ld\n", LONG_MAX);
|
||||
|
||||
/* long long (int): */
|
||||
|
||||
printf("lld LLONG_MAX = %lld\n", LLONG_MAX);
|
||||
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);
|
||||
printf("printf float = %f\n", 1.0f);
|
||||
printf("printf double = %f\n", 1.0);
|
||||
|
||||
/* long double: */
|
||||
|
||||
printf("f = %Lf\n", (long double)1.0);
|
||||
printf("f = %Lf\n", (long double)1.0);
|
||||
|
||||
/* # control number of zeros after dot */
|
||||
{
|
||||
@ -7160,7 +7288,7 @@ int main(int argc, char **argv) {
|
||||
#endif
|
||||
|
||||
/*
|
||||
pointers
|
||||
# printf Pointers
|
||||
|
||||
prints the hexadeciamal linear address.
|
||||
|
||||
@ -7230,7 +7358,7 @@ int main(int argc, char **argv) {
|
||||
#endif
|
||||
|
||||
/*
|
||||
# escape percentage.
|
||||
# Escape percentage.
|
||||
|
||||
Note that `%` is printf specific,
|
||||
not string literal specific,
|
||||
@ -7497,7 +7625,9 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
/*
|
||||
# file streams #file io
|
||||
# File streams
|
||||
|
||||
# File IO
|
||||
|
||||
To get streams that deal with files, use `fopen`.
|
||||
|
||||
@ -7530,16 +7660,16 @@ int main(int argc, char **argv) {
|
||||
|
||||
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.
|
||||
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 IO vs # Binary IO
|
||||
|
||||
# text vs binary for numerical types
|
||||
# Text vs binary for numerical types
|
||||
|
||||
Example: an int 123 can be written to a file in two ways:
|
||||
|
||||
@ -7557,7 +7687,7 @@ int main(int argc, char **argv) {
|
||||
- it much shorter for large integers
|
||||
- inevitable for data that cannot be interpretred as text (images, executables)
|
||||
|
||||
# newline vs carriage return newline
|
||||
# Newline vs carriage return newline
|
||||
|
||||
Newline carriage return realated TODO confirm
|
||||
|
||||
@ -7592,13 +7722,16 @@ int main(int argc, char **argv) {
|
||||
|
||||
Returns number of elements written.
|
||||
|
||||
If less elements are written than required an erro ocurred.
|
||||
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>
|
||||
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");
|
||||
@ -7646,6 +7779,34 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -7658,7 +7819,7 @@ int main(int argc, char **argv) {
|
||||
/*freopen("/dev/null", "r", stdin);*/
|
||||
}
|
||||
|
||||
/* # reposition read write */
|
||||
/* # Reposition read write */
|
||||
{
|
||||
/*
|
||||
For new code, always use `fgetpos` and `fsetpos` unless you absolutely
|
||||
@ -9059,27 +9220,43 @@ int main(int argc, char **argv) {
|
||||
in the current architecure
|
||||
*/
|
||||
{
|
||||
/* # INT_MAX #UINT_MAX */
|
||||
printf("CHAR_MAX = %d\n", CHAR_MAX);
|
||||
assert(CHAR_MAX == 127);
|
||||
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);
|
||||
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);
|
||||
printf(" UINT_MAX = %u\n", UINT_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
# float.h
|
||||
|
||||
gives characteristics of floating point numbers and of base numerical operations
|
||||
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:
|
||||
@ -9088,6 +9265,7 @@ int main(int argc, char **argv) {
|
||||
- LDBL for `long double`
|
||||
*/
|
||||
{
|
||||
puts("float.h");
|
||||
|
||||
/*
|
||||
# FLT_ROUNDS
|
||||
@ -9105,7 +9283,7 @@ int main(int argc, char **argv) {
|
||||
TODO0 can it be changed?
|
||||
*/
|
||||
{
|
||||
printf("FLT_ROUNDS = %d\n", FLT_ROUNDS);
|
||||
printf(" FLT_ROUNDS = %d\n", FLT_ROUNDS);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -9119,7 +9297,7 @@ int main(int argc, char **argv) {
|
||||
TODO0 understand better
|
||||
*/
|
||||
{
|
||||
printf("FLT_EVAL_METHOD = %d\n", FLT_EVAL_METHOD);
|
||||
printf(" FLT_EVAL_METHOD = %d\n", FLT_EVAL_METHOD);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -9131,9 +9309,9 @@ int main(int argc, char **argv) {
|
||||
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);
|
||||
printf(" FLT_MIN = %a\n", FLT_MIN);
|
||||
printf(" DBL_MIN = %a\n", DBL_MIN);
|
||||
printf(" LDBL_MIN = %La\n", LDBL_MIN);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -9150,7 +9328,7 @@ int main(int argc, char **argv) {
|
||||
TODO0 wow, there are non radix 2 representation implementations?!
|
||||
*/
|
||||
{
|
||||
printf("FLT_RADIX = %d\n", FLT_RADIX);
|
||||
printf(" FLT_RADIX = %d\n", FLT_RADIX);
|
||||
}
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
@ -9196,15 +9374,15 @@ int main(int argc, char **argv) {
|
||||
- 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);
|
||||
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);
|
||||
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));
|
||||
@ -9593,7 +9771,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
/*
|
||||
# main return #return
|
||||
# main return
|
||||
|
||||
Valid returns are:
|
||||
|
||||
|
56
cpp.cpp
56
cpp.cpp
@ -159,62 +159,6 @@ Features which are identical to C will not be described.
|
||||
- <http://stackoverflow.com/questions/6163683/cycles-in-family-tree-software>
|
||||
|
||||
Funny...
|
||||
|
||||
# Sources
|
||||
|
||||
# Free
|
||||
|
||||
- <http://www.cplusplus.com>
|
||||
|
||||
Explains well what most the features of the language do for beginners.
|
||||
|
||||
Not official in any way, despite the amazing url and google rank.
|
||||
|
||||
Is said to contain many errors, and that cppreference is superior.
|
||||
|
||||
- <http://en.cppreference.com/w/>
|
||||
|
||||
Similar to cplusplus.com, but seems to have more info.
|
||||
|
||||
Wiki driven.
|
||||
|
||||
Attempts to document all the language and stdlibs.
|
||||
|
||||
Many behaviour examples.
|
||||
|
||||
- <http://www.parashift.com/c++-faq/index.html>
|
||||
|
||||
C++ faq.
|
||||
|
||||
Deep and extensive tutorial.
|
||||
|
||||
- <http://herbsutter.com/gotw/>
|
||||
|
||||
Herb Sutter Guru of the week.
|
||||
|
||||
Hard topics with simple examples.
|
||||
|
||||
- <http://yosefk.com/c++fqa/>
|
||||
|
||||
Comments on the quirks of c++.
|
||||
|
||||
Fun and informative for those that know the language at intermediate level.
|
||||
|
||||
- <http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp>
|
||||
|
||||
IBM implementation of C++.
|
||||
|
||||
Contains a few extension, but lots of well explained docs with many examples.
|
||||
|
||||
Contains clear examples and explanations on very specific subjects.
|
||||
|
||||
Horrible navigation and urls.
|
||||
|
||||
# Non-free
|
||||
|
||||
- <http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list>
|
||||
|
||||
List of books.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
244
gcc/main.c
244
gcc/main.c
@ -12,30 +12,29 @@ int nested() {
|
||||
|
||||
/* Attribute */
|
||||
|
||||
/* # Function attributes */
|
||||
|
||||
char not_aligned16 = 0;
|
||||
char aligned16 __attribute__ ((aligned (16))) = 0;
|
||||
|
||||
int sprintf_wrapper(char *s, int useless, const char *fmt, int useless2, ...) {
|
||||
int ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, useless2);
|
||||
ret = vsprintf(s, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Format */
|
||||
|
||||
int sprintf_wrapper(char *s, int useless, const char *fmt, int useless2, ...) {
|
||||
int ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, useless2);
|
||||
ret = vsprintf(s, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
3 says: the 3rd argument is the format string
|
||||
5 says: the va_list starts at the 5th argument
|
||||
|
||||
Declaration and definition *must* be separated.
|
||||
*/
|
||||
int sprintf_wrapper_attr(char *s, int useless, const char *fmt, int useless2, ...) __attribute__((format(printf, 3, 5)));
|
||||
int sprintf_wrapper_attr(char *s, int useless, const char *fmt, int useless2, ...)
|
||||
__attribute__((format(printf, 3, 5)));
|
||||
|
||||
int sprintf_wrapper_attr(char *s, int useless, const char *fmt, int useless2, ...) {
|
||||
int ret;
|
||||
@ -61,7 +60,7 @@ int nested() {
|
||||
|
||||
void func_not_used(){}
|
||||
|
||||
//warn_unused_result
|
||||
/* warn_unused_result */
|
||||
|
||||
int func_warn_unused_result() __attribute__((warn_unused_result));
|
||||
int func_warn_unused_result(){ return 0; }
|
||||
@ -84,7 +83,7 @@ int nested() {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
//WARNING: control reaches end of non void function
|
||||
/* WARNING: control reaches end of non void function */
|
||||
/*
|
||||
int noreturn_possible(int n) {
|
||||
if (n > 0)
|
||||
@ -288,10 +287,11 @@ int main() {
|
||||
|
||||
/* This would cause a redefinition error: */
|
||||
|
||||
//int nested()
|
||||
//{
|
||||
// return 2;
|
||||
//}
|
||||
/*
|
||||
int nested() {
|
||||
return 2;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Like variable redefinitions, the nested version overrides all external version */
|
||||
/* which have become completelly innacessible */
|
||||
@ -302,7 +302,7 @@ int main() {
|
||||
/*
|
||||
# Preprocessor defines
|
||||
|
||||
Full list: <http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros>
|
||||
Full list: http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros
|
||||
|
||||
View all macros that would be automatically defined:
|
||||
|
||||
@ -318,7 +318,7 @@ int main() {
|
||||
`__GNUC_MINOR__` : minor
|
||||
`__GNUC_PATCHLEVEL__`: patch
|
||||
|
||||
<http://stackoverflow.com/questions/259248/how-do-i-test-the-current-version-of-gcc>
|
||||
http://stackoverflow.com/questions/259248/how-do-i-test-the-current-version-of-gcc
|
||||
|
||||
There is also:
|
||||
|
||||
@ -355,17 +355,27 @@ int main() {
|
||||
#endif
|
||||
|
||||
/*
|
||||
gcc defines architecture macros TODO where?
|
||||
# Architecture detection macro
|
||||
|
||||
you can find a list of those macros: <http://sourceforge.net/p/predef/wiki/Architectures/>
|
||||
http://stackoverflow.com/questions/152016/detecting-cpu-architecture-compile-time
|
||||
|
||||
GCC defines architecture macros TODO where?
|
||||
|
||||
Seems to use the list: http://sourceforge.net/p/predef/wiki/Architectures/
|
||||
*/
|
||||
|
||||
#ifdef __i386__
|
||||
puts("__i386__");
|
||||
#elif __x86_64__
|
||||
puts("__x86_64__");
|
||||
#endif
|
||||
|
||||
/*
|
||||
gcc defines OS macros TODO where?
|
||||
# OS detection macro
|
||||
|
||||
http://stackoverflow.com/questions/142508/how-do-i-check-os-with-a-preprocessor-directive
|
||||
|
||||
Same riddle as architecture detection.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
@ -376,6 +386,8 @@ int main() {
|
||||
/*
|
||||
# Attribute
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html#Attribute-Syntax
|
||||
|
||||
Specifies special attributes of functions or data.
|
||||
|
||||
There are three types of attributes:
|
||||
@ -408,7 +420,7 @@ int main() {
|
||||
[[vendor::attr5]] return i;
|
||||
}
|
||||
|
||||
and two attributes; noreturn and carries_dependency.
|
||||
and two attributes; `noreturn` and `carries_dependency`.
|
||||
|
||||
# Multiple attributes
|
||||
|
||||
@ -427,7 +439,7 @@ int main() {
|
||||
|
||||
See next section.
|
||||
|
||||
# Eliminating __attribute__ on non gnu projects
|
||||
# Eliminating __attribute__ on non-GNU projects
|
||||
|
||||
This is really easy:
|
||||
|
||||
@ -445,110 +457,117 @@ int main() {
|
||||
*/
|
||||
{
|
||||
/*
|
||||
# format
|
||||
# Function attributes
|
||||
|
||||
If this is used, gcc can check if printf format strings are correct because of the use of attributes,
|
||||
and emmit errors otherwise.
|
||||
https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
||||
*/
|
||||
{
|
||||
char s[32];
|
||||
sprintf_wrapper(s, 0, "%c", 0, 'a');
|
||||
assert(s[0] == 'a');
|
||||
|
||||
sprintf_wrapper_attr(s, 0, "%c", 0, 'b');
|
||||
assert(s[0] == 'b');
|
||||
|
||||
/*
|
||||
With `__attribute__((format,X,Y))` the compile time error checking gets done.
|
||||
# format
|
||||
|
||||
If this is used, gcc can check if printf format strings are correct because of the use of attributes,
|
||||
and emmit errors otherwise.
|
||||
*/
|
||||
{
|
||||
//compile error check not done
|
||||
//could segfault at runtime
|
||||
if (0) {
|
||||
sprintf_wrapper(s, 0, "%s", 0);
|
||||
}
|
||||
char s[32];
|
||||
sprintf_wrapper(s, 0, "%c", 0, 'a');
|
||||
assert(s[0] == 'a');
|
||||
|
||||
//compile error check is done
|
||||
sprintf_wrapper_attr(s, 0, "%c", 0, 'b');
|
||||
assert(s[0] == 'b');
|
||||
|
||||
/*
|
||||
With `__attribute__((format,X,Y))` the compile time error checking gets done.
|
||||
*/
|
||||
{
|
||||
//sprintf_wrapper_attr(s, 0, "%s", 0);
|
||||
/* Compile error check not done. */
|
||||
/* Could segfault at runtime. */
|
||||
if (0) {
|
||||
sprintf_wrapper(s, 0, "%s", 0);
|
||||
}
|
||||
|
||||
/* Compile error check is done. */
|
||||
{
|
||||
/*sprintf_wrapper_attr(s, 0, "%s", 0);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
# deprecated
|
||||
/*
|
||||
# deprecated
|
||||
|
||||
Using a function marked as deprecated will emmit warnings.
|
||||
*/
|
||||
{
|
||||
//func_deprecated();
|
||||
}
|
||||
Using a function marked as deprecated will emmit warnings.
|
||||
*/
|
||||
{
|
||||
/*func_deprecated();*/
|
||||
}
|
||||
|
||||
/*
|
||||
# used
|
||||
/*
|
||||
# used
|
||||
|
||||
Useful when the function may be called from assembly code, in which case GCC
|
||||
may not be easily able to detect that it was called.
|
||||
Useful when the function may be called from assembly code, in which case GCC
|
||||
may not be easily able to detect that it was called.
|
||||
|
||||
TODO0 what is this for? If a func is not called, what does gcc do? Remove it from text?
|
||||
*/
|
||||
{
|
||||
}
|
||||
TODO0 what is this for? If a func is not called, what does gcc do? Remove it from text?
|
||||
*/
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
# warn_unused_result
|
||||
/*
|
||||
# warn_unused_result
|
||||
|
||||
Always emmit a warning if the return value is not used.
|
||||
Always emmit a warning if the return value is not used.
|
||||
|
||||
Useful to enforce callers to do error checks when the return value signals the error.
|
||||
*/
|
||||
{
|
||||
/* No warning. */
|
||||
func_not_warn_unused_result();
|
||||
Useful to enforce callers to do error checks when the return value signals the error.
|
||||
*/
|
||||
{
|
||||
/* No warning. */
|
||||
func_not_warn_unused_result();
|
||||
|
||||
assert(func_warn_unused_result() == 0);
|
||||
assert(func_warn_unused_result() == 0);
|
||||
|
||||
//WARNING ignored return value
|
||||
/* WARNING ignored return value */
|
||||
|
||||
//func_warn_unused_result();
|
||||
}
|
||||
/*func_warn_unused_result();*/
|
||||
}
|
||||
|
||||
/*
|
||||
# const
|
||||
/*
|
||||
# const
|
||||
|
||||
A function marked const may be optimized in the sense that the compiler calculates its value at compile time,
|
||||
or chaches its result of each calculation.
|
||||
A function marked const may be optimized in the sense that the compiler calculates its value at compile time,
|
||||
or chaches its result of each calculation.
|
||||
|
||||
A function can only be marked const if:
|
||||
A function can only be marked const if:
|
||||
|
||||
- its return value is only a function of its arguments, and not of any global or static function variable
|
||||
- the function has no desired side effect besides returning the value
|
||||
- its return value is only a function of its arguments, and not of any global or static function variable
|
||||
- the function has no desired side effect besides returning the value
|
||||
|
||||
Marking a function which does one of the above const will lead to serious hard to find bugs.
|
||||
*/
|
||||
{
|
||||
assert(next(0) == 1);
|
||||
assert(next(0) == 1);
|
||||
assert(next_const(0) == 1);
|
||||
assert(next_const(0) == 1);
|
||||
}
|
||||
Marking a function which does one of the above const will lead to serious hard to find bugs.
|
||||
*/
|
||||
{
|
||||
assert(next(0) == 1);
|
||||
assert(next(0) == 1);
|
||||
assert(next_const(0) == 1);
|
||||
assert(next_const(0) == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
# always_inline
|
||||
/*
|
||||
# always_inline
|
||||
|
||||
Always inline the function.
|
||||
Always inline the function.
|
||||
|
||||
ANSI C99 `inline` does not guarantee that, it only hints it to the compiler.
|
||||
ANSI C99 `inline` does not guarantee that, it only hints it to the compiler.
|
||||
|
||||
Must see generated assembly code to notice this (except for the possible desired speedup effect).
|
||||
Must see generated assembly code to notice this (except for the possible desired speedup effect).
|
||||
|
||||
On `gcc -O0 4.7`, only the `incr_always_inline` was inlined.
|
||||
*/
|
||||
{
|
||||
int i = 0;
|
||||
i = incr(i);
|
||||
i = incr_inline(i);
|
||||
i = incr_always_inline(i);
|
||||
On `gcc -O0 4.7`, only the `incr_always_inline` was inlined.
|
||||
*/
|
||||
{
|
||||
int i = 0;
|
||||
i = incr(i);
|
||||
i = incr_inline(i);
|
||||
i = incr_always_inline(i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -612,7 +631,7 @@ int main() {
|
||||
|
||||
GCC built-ins for vectorized SIMD operations.
|
||||
|
||||
<http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html>
|
||||
http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
|
||||
|
||||
Allowed operators: +, -, *, /, unary minus, ^, |, &, ~, %, ==, !=, <, <=, >, >=
|
||||
|
||||
@ -658,7 +677,7 @@ int main() {
|
||||
|
||||
# asm
|
||||
|
||||
Great intro: <http://www.ibm.com/developerworks/library/l-ia/index.html>
|
||||
Great intro: http://www.ibm.com/developerworks/library/l-ia/index.html
|
||||
|
||||
Can be used if you really, really want to optimize at the cost of:
|
||||
|
||||
@ -682,10 +701,13 @@ int main() {
|
||||
|
||||
where:
|
||||
|
||||
- commands: actual gas code into a single c string. Remember: each command has to end in newline or `;`.
|
||||
- outputs: start with `=`. gcc has to enforce is that at the end of the `asm` block that those values are set.
|
||||
- inputs:
|
||||
- clobbered registers:
|
||||
- commands: actual gas code into a single c string. Remember: each command has to end in newline or `;`.
|
||||
|
||||
- outputs: start with `=`. gcc has to enforce is that at the end of the `asm` block that those values are set.
|
||||
|
||||
- inputs:
|
||||
|
||||
- clobbered registers:
|
||||
|
||||
Registers that may be modified explicitly in the assembly code.
|
||||
|
||||
@ -728,7 +750,7 @@ int main() {
|
||||
{
|
||||
int in = 1;
|
||||
int out = 0;
|
||||
//out = in
|
||||
/*out = in*/
|
||||
asm volatile (
|
||||
"movl %1, %%eax;"
|
||||
"movl %%eax, %0"
|
||||
@ -742,7 +764,7 @@ int main() {
|
||||
/* No input. */
|
||||
{
|
||||
int out = 0;
|
||||
//out = 1
|
||||
/*out = 1*/
|
||||
asm volatile (
|
||||
"movl $1, %0"
|
||||
: "=m" (out)
|
||||
@ -754,7 +776,7 @@ int main() {
|
||||
{
|
||||
float in = 1.0;
|
||||
float out = 0.0;
|
||||
//out = -in
|
||||
/*out = -in*/
|
||||
asm volatile (
|
||||
"flds %1;"
|
||||
"fchs;"
|
||||
@ -768,7 +790,7 @@ int main() {
|
||||
/* Input and ouput can be the same memory location. */
|
||||
{
|
||||
float x = 1.0;
|
||||
//x = -x
|
||||
/*x = -x*/
|
||||
asm (
|
||||
"flds %1;"
|
||||
"fchs;"
|
||||
@ -810,7 +832,7 @@ int main() {
|
||||
{
|
||||
int in = 0;
|
||||
int out = 0;
|
||||
//out = in + 2
|
||||
/*out = in + 2*/
|
||||
asm (
|
||||
"incl %1;"
|
||||
"movl %1, %0;"
|
||||
@ -924,7 +946,7 @@ int main() {
|
||||
Get address that function will return to after return.
|
||||
|
||||
It seems that it is not possible to jump to a location without assemby:
|
||||
<http://stackoverflow.com/questions/8158007/how-to-jump-the-program-execution-to-a-specific-address-in-c>
|
||||
http://stackoverflow.com/questions/8158007/how-to-jump-the-program-execution-to-a-specific-address-in-c
|
||||
|
||||
This is most useful for debugging.
|
||||
*/
|
||||
|
6
gdb.md
6
gdb.md
@ -155,6 +155,12 @@ So here we see that:
|
||||
|
||||
TODO understand everything
|
||||
|
||||
## Step backwards in time
|
||||
|
||||
## Omniscient debugging
|
||||
|
||||
Considered a "high priority project" by the FSF as of January 2015 <http://www.fsf.org/campaigns/priority-projects/reversible-debugging-in-gdb>
|
||||
|
||||
---
|
||||
|
||||
TODO format the rest of this section as md:
|
||||
|
35
getting-started.md
Normal file
35
getting-started.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Getting started
|
||||
|
||||
## Dependencies
|
||||
|
||||
Most builds require:
|
||||
|
||||
- `make` (POSIX)
|
||||
- `gcc` >= 4.7
|
||||
- `g++` >= 4.7
|
||||
|
||||
Even though we use GNU tools by default, great attention is paid to portability of portable subjects like ANSI C, which should compile in any compiler.
|
||||
|
||||
In addition, each directory may have their own extra dependencies as stated in their README.
|
||||
|
||||
You can install dependencies on latest LTS Ubuntus with:
|
||||
|
||||
./configure
|
||||
|
||||
Other system install are not going to be supported as that would lead to too much maintenance overhead. If you don't have Ubuntu, consider using our [Vagrantfile](Vagrantfile).
|
||||
|
||||
## Usage
|
||||
|
||||
When there are multiple files compiled, e.g.:
|
||||
|
||||
c.c -> c
|
||||
cpp.cpp -> cpp
|
||||
|
||||
run a given file by specifying the basename without extension:
|
||||
|
||||
make run=c
|
||||
make run=cpp
|
||||
|
||||
The `=` sign is *not* optional!
|
||||
|
||||
Doing just `make run` in those cases will run the default file: `main`.
|
@ -2,4 +2,5 @@
|
||||
|
||||
int main() {
|
||||
puts("Hello world C.");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1 +1,9 @@
|
||||
# POSIX C API
|
||||
|
||||
## Bibliography
|
||||
|
||||
- <http://www.amazon.com/Beginning-Linux-Programming-Neil-Matthew/dp/0470147628>
|
||||
|
||||
Matthew; Stones - Beginning Linux Programming.
|
||||
|
||||
Very good intro do many of POSIX utilities with interesting examples and topics.
|
||||
|
123
posix/main.c
123
posix/main.c
@ -426,6 +426,8 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
/*
|
||||
# File IO
|
||||
|
||||
# File descriptors
|
||||
|
||||
`int` identifier to a data stream.
|
||||
@ -481,29 +483,30 @@ int main(int argc, char** argv) {
|
||||
|
||||
Flags. Must specify one and only of the following:
|
||||
|
||||
- O_WRONLY: write only
|
||||
- O_RDONLY: read only.
|
||||
- `O_WRONLY`: write only
|
||||
|
||||
- `O_RDONLY`: read only.
|
||||
|
||||
Undefined behaviour with O_TRUNC.
|
||||
|
||||
TODO0 can be used with O_CREAT?
|
||||
|
||||
- O_RDWR: read and write
|
||||
- `O_RDWR`: read and write
|
||||
|
||||
Other important flags.
|
||||
|
||||
- O_APPEND: If the file exists, open fd at the end of the file.
|
||||
- `O_APPEND`: If the file exists, open fd at the end of the file.
|
||||
|
||||
- O_TRUNC: If the file exists, open fd at the end of the file,
|
||||
- `O_TRUNC`: If the file exists, open fd at the end of the file,
|
||||
set its length to zero, discarding existing contents.
|
||||
|
||||
Undefined behaviour with O_RDONLY.
|
||||
|
||||
- O_CREAT: If the file does not exit, creat it, with permissions given in mode.
|
||||
- `O_CREAT`: If the file does not exit, creat it, with permissions given in mode.
|
||||
|
||||
Mode must be specified when this flag is set, and is ignored if this is not set.
|
||||
|
||||
- O_EXCL: Used with O_CREAT, ensures that the caller creates the file.
|
||||
- `O_EXCL`: Used with O_CREAT, ensures that the caller creates the file.
|
||||
|
||||
The open is atomic; that is, no two opens can open at the same time.
|
||||
|
||||
@ -716,7 +719,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
//read
|
||||
/* read */
|
||||
{
|
||||
fd = open(fname, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
@ -741,7 +744,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
//BAD forget O_CREAT on non-existent file gives ENOENT
|
||||
/* BAD forget O_CREAT on non-existent file gives ENOENT */
|
||||
{
|
||||
fd = open("/i/do/not/exist", O_RDONLY, S_IRWXU);
|
||||
if (fd == -1) {
|
||||
@ -751,7 +754,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
//BAD write on a O_RDONLY fd gives errno EBADF
|
||||
/* BAD write on a O_RDONLY fd gives errno EBADF */
|
||||
{
|
||||
int fd;
|
||||
char *fname = "write_rdonly.tmp";
|
||||
@ -785,13 +788,15 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
/*
|
||||
open and write without truncate
|
||||
Open and write without truncate.
|
||||
|
||||
after write 1: abcd
|
||||
after write 2: 01cd
|
||||
Output:
|
||||
|
||||
after write 1: abcd
|
||||
after write 2: 01cd
|
||||
*/
|
||||
{
|
||||
//set file to abc
|
||||
/* Set file to `abc`. */
|
||||
{
|
||||
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
|
||||
if (fd == -1) {
|
||||
@ -809,7 +814,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
//open and write to it without truncating
|
||||
/* Open and write to it without truncating. */
|
||||
{
|
||||
fd = open(fname, O_RDWR);
|
||||
if (fd == -1) {
|
||||
@ -823,7 +828,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
//check the new result
|
||||
/* Check the new result. */
|
||||
{
|
||||
if (lseek(fd, 0, SEEK_SET) != 0) {
|
||||
perror("lseek");
|
||||
@ -833,7 +838,7 @@ int main(int argc, char** argv) {
|
||||
perror("read");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
//the first two bytes were overwriten
|
||||
/* The first two bytes were overwriten. */
|
||||
assert(memcmp(out, "01cd", nbytes) == 0);
|
||||
}
|
||||
if (close(fd) == -1) {
|
||||
@ -864,7 +869,7 @@ int main(int argc, char** argv) {
|
||||
perror("write");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Read after eof, return 0 and read nothing.
|
||||
/* Read after eof, return 0 and read nothing. */
|
||||
if (read(fd, out, 1) != 0) {
|
||||
assert(false);
|
||||
}
|
||||
@ -872,7 +877,7 @@ int main(int argc, char** argv) {
|
||||
perror("lseek");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Byte 0 was never writen, so reading it returns `(int)0`.
|
||||
/* Byte 0 was never writen, so reading it returns `(int)0`. */
|
||||
if (read(fd, out, 2) != 2) {
|
||||
perror("read");
|
||||
exit(EXIT_FAILURE);
|
||||
@ -908,6 +913,39 @@ int main(int argc, char** argv) {
|
||||
printf("STDOUT_FILENO = %d\n", STDOUT_FILENO);
|
||||
printf("STDERR_FILENO = %d\n", STDERR_FILENO);
|
||||
}
|
||||
|
||||
/*
|
||||
# aio family
|
||||
|
||||
# Asynchronous IO
|
||||
|
||||
# aio_cancel
|
||||
|
||||
# aio_error
|
||||
|
||||
# aio_fsync
|
||||
|
||||
# aio_read
|
||||
|
||||
# aio_return
|
||||
|
||||
# aio_suspend
|
||||
|
||||
# aio_write
|
||||
|
||||
Great soruce: <http://www.fsl.cs.sunysb.edu/~vass/linux-aio.txt>
|
||||
|
||||
In Linux, implemented with the system calls:
|
||||
|
||||
io_cancel(2) 2.6
|
||||
io_destroy(2) 2.6
|
||||
io_getevents(2) 2.6
|
||||
io_setup(2) 2.6
|
||||
io_submit(2) 2.6
|
||||
*/
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -937,7 +975,7 @@ int main(int argc, char** argv) {
|
||||
char *oldpath = "link_old.tmp";
|
||||
char *newpath = "link_new.tmp";
|
||||
|
||||
// Create old.
|
||||
/* Create old. */
|
||||
fd = open(oldpath, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
|
||||
if (fd == -1) {
|
||||
perror("open");
|
||||
@ -1034,16 +1072,17 @@ int main(int argc, char** argv) {
|
||||
TODO application?
|
||||
*/
|
||||
{
|
||||
char *filepath = "mmap.tmp";
|
||||
char* filepath = "mmap.tmp";
|
||||
int numints = 4;
|
||||
int filesize = numints * sizeof(int);
|
||||
|
||||
int i;
|
||||
int fd;
|
||||
int result;
|
||||
int *map; /* mmapped array of int's */
|
||||
/* mmapped array of int's */
|
||||
int* map;
|
||||
|
||||
// Write to file with mmap.
|
||||
/* Write to file with mmap. */
|
||||
{
|
||||
/* `O_WRONLY` is not sufficient when mmaping, need `O_RDWR`.*/
|
||||
fd = open(filepath, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
|
||||
@ -1094,7 +1133,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
// Read result back in.
|
||||
/* Read result back in. */
|
||||
{
|
||||
fd = open(filepath, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
@ -1111,9 +1150,9 @@ int main(int argc, char** argv) {
|
||||
|
||||
assert(map[1] == 1);
|
||||
|
||||
// Segmentation fault because no `PROT_WRITE`:
|
||||
/* Segmentation fault because no `PROT_WRITE`: */
|
||||
{
|
||||
//map[1] = 2;
|
||||
/*map[1] = 2;*/
|
||||
}
|
||||
|
||||
if (munmap(map, filesize) == -1) {
|
||||
@ -1137,7 +1176,7 @@ int main(int argc, char** argv) {
|
||||
TODO0 application?
|
||||
*/
|
||||
{
|
||||
// Private write
|
||||
/* Private write */
|
||||
{
|
||||
fd = open(filepath, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
@ -1165,7 +1204,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
// Read
|
||||
/* Read */
|
||||
{
|
||||
fd = open(filepath, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
@ -1180,7 +1219,7 @@ int main(int argc, char** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//did not change!
|
||||
/* Did not change! */
|
||||
assert(map[0] == 0);
|
||||
|
||||
if (munmap(map, filesize) == -1) {
|
||||
@ -1196,7 +1235,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
//#pathname operations
|
||||
/* # Pathname operations */
|
||||
{
|
||||
/*
|
||||
# realpath
|
||||
@ -1285,7 +1324,6 @@ int main(int argc, char** argv) {
|
||||
- portable lightweight: dirent.h
|
||||
*/
|
||||
{
|
||||
|
||||
/*
|
||||
# stat family
|
||||
|
||||
@ -1396,7 +1434,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
//#mkdir
|
||||
/* # mkdir */
|
||||
{
|
||||
struct stat s;
|
||||
char fname[] = "mkdir";
|
||||
@ -1410,7 +1448,7 @@ int main(int argc, char** argv) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
//#rmdir
|
||||
/* # rmdir */
|
||||
{
|
||||
mkdir("rmdir", 0777);
|
||||
if(rmdir("rmdir") == -1)
|
||||
@ -1556,11 +1594,10 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
// OK, enough of error checking from now on.
|
||||
|
||||
/* OK, enough of error checking from now on. */
|
||||
printf("RLIM_INFINITY = %ju\n", (uintmax_t)RLIM_INFINITY);
|
||||
|
||||
// maximum total CPU usage in seconds.
|
||||
/* maximum total CPU usage in seconds. */
|
||||
getrlimit(RLIMIT_CPU, &limit);
|
||||
printf(
|
||||
"RLIMIT_CPU\n soft = %ju\n hard = %ju\n",
|
||||
@ -1568,7 +1605,7 @@ int main(int argc, char** argv) {
|
||||
(uintmax_t)limit.rlim_max
|
||||
);
|
||||
|
||||
// Maximum file size in bytes.
|
||||
/* Maximum file size in bytes. */
|
||||
getrlimit(RLIMIT_FSIZE, &limit);
|
||||
printf(
|
||||
"RLIMIT_FSIZE\n soft = %ju\n hard = %ju\n",
|
||||
@ -1576,7 +1613,7 @@ int main(int argc, char** argv) {
|
||||
(uintmax_t)limit.rlim_max
|
||||
);
|
||||
|
||||
// Number of file descriptors:
|
||||
/* Number of file descriptors: */
|
||||
getrlimit(RLIMIT_NOFILE, &limit);
|
||||
printf(
|
||||
"RLIMIT_NOFILE\n soft = %ju\n hard = %ju\n",
|
||||
@ -1660,13 +1697,11 @@ int main(int argc, char** argv) {
|
||||
Similar to sysconf, but for parameters that depend on a path, such as maxium filename lengths.
|
||||
*/
|
||||
{
|
||||
// Max basename in given dir including trailling null:
|
||||
/* Max basename in given dir including trailling null: */
|
||||
printf("pathconf(\".\", _PC_NAME_MAX) = %ld\n", pathconf(".", _PC_NAME_MAX));
|
||||
|
||||
printf("pathconf(\".\", _PC_NAME_MAX) = %ld\n", pathconf(".", _PC_NAME_MAX));
|
||||
|
||||
// Max pathname in (TODO this is per device?)
|
||||
|
||||
printf("pathconf(\".\", _PC_PATH_MAX) = %ld\n", pathconf(".", _PC_PATH_MAX));
|
||||
/* Max pathname in (TODO this is per device?) */
|
||||
printf("pathconf(\".\", _PC_PATH_MAX) = %ld\n", pathconf(".", _PC_PATH_MAX));
|
||||
}
|
||||
}
|
||||
|
||||
|
206
posix/signal.c
206
posix/signal.c
@ -10,159 +10,163 @@ To send arbitrary signals to a process from a terminal, consider using the `kill
|
||||
Also consider the convenient non POSIX stadardized VT100 control characters such as `<C-C>`
|
||||
which generate certain signals such as `SIGTERM`.
|
||||
|
||||
#ANSI
|
||||
# ANSI signals
|
||||
|
||||
ANSI C supports the concept of signals, and only POSIX specific features shall be discussed here.
|
||||
ANSI C supports the concept of signals, and only POSIX specific features shall be discussed here.
|
||||
|
||||
Please look for ANSI C info for any feature used but not explained here.
|
||||
Please look for ANSI C info for any feature used but not explained here.
|
||||
|
||||
Linux extends POSIX by adding new signals, Those shall not be discussed here.
|
||||
Linux extends POSIX by adding new signals, Those shall not be discussed here.
|
||||
|
||||
#POSIX
|
||||
# POSIX signals
|
||||
|
||||
Docs here: <http://pubs.opengroup.org/onlinepubs/009696699/basedefs/signal.h.html>.
|
||||
Docs here: http://pubs.opengroup.org/onlinepubs/009696699/basedefs/signal.h.html
|
||||
|
||||
POSIX defines several signals in addition to the ANSI C signals.
|
||||
POSIX defines several signals in addition to the ANSI C signals.
|
||||
|
||||
As in ANSI C, each signal has the following attributes:
|
||||
As in ANSI C, each signal has the following attributes:
|
||||
|
||||
- general description of which conditions generate the signal
|
||||
- general description of which conditions generate the signal
|
||||
|
||||
- the signal can or cannot be handled.
|
||||
- the signal can or cannot be handled.
|
||||
|
||||
Most signals can be handled, but there are a few exceptions such as:
|
||||
Most signals can be handled, but there are a few exceptions such as:
|
||||
|
||||
- `SIGKILL`: always kill processes, cannot be handled.
|
||||
- `SIGKSTOP` and `SIGCONT`
|
||||
- `SIGKILL`: always kill processes, cannot be handled.
|
||||
- `SIGKSTOP` and `SIGCONT`
|
||||
|
||||
- default action to take
|
||||
- default action to take
|
||||
|
||||
For signals that can be handled, you can change those behavious by creating your own handlers.
|
||||
For signals that can be handled, you can change those behavious by creating your own handlers.
|
||||
|
||||
The possible default behaviours are:
|
||||
The possible default behaviours are:
|
||||
|
||||
- T:
|
||||
- T:
|
||||
|
||||
Abnormal termination of the process.
|
||||
Abnormal termination of the process.
|
||||
|
||||
The process is terminated with all the consequences of `_exit()` except that the status made available to
|
||||
`wait()` and `waitpid()` indicates abnormal termination by the specified signal.
|
||||
The process is terminated with all the consequences of `_exit()` except that the status made available to
|
||||
`wait()` and `waitpid()` indicates abnormal termination by the specified signal.
|
||||
|
||||
Default action for most signals.
|
||||
Default action for most signals.
|
||||
|
||||
- A :Abnormal termination of the process.
|
||||
- A :Abnormal termination of the process.
|
||||
|
||||
[XSI] [Option Start] Additionally, implementation-defined abnormal termination actions,
|
||||
such as creation of a core file, may occur. [Option End]
|
||||
[XSI] [Option Start] Additionally, implementation-defined abnormal termination actions,
|
||||
such as creation of a core file, may occur. [Option End]
|
||||
|
||||
Linux implements concept of core dumps on those cases.
|
||||
Note however that those may be turned on or off depending on the system configuration.
|
||||
Linux implements concept of core dumps on those cases.
|
||||
Note however that those may be turned on or off depending on the system configuration.
|
||||
|
||||
- I: Ignore the signal.
|
||||
- I: Ignore the signal.
|
||||
|
||||
An important example is `SIGCHLD`, which is generated when a child terminates,
|
||||
but has no effect by default, since in general killing the parent is not what
|
||||
should happen on most programs.
|
||||
An important example is `SIGCHLD`, which is generated when a child terminates,
|
||||
but has no effect by default, since in general killing the parent is not what
|
||||
should happen on most programs.
|
||||
|
||||
- S: Stop the process.
|
||||
- S: Stop the process.
|
||||
|
||||
Mainly `SIGSTOP`.
|
||||
Mainly `SIGSTOP`.
|
||||
|
||||
- C: Continue the process, if it is stopped; otherwise, ignore the signal.
|
||||
- C: Continue the process, if it is stopped; otherwise, ignore the signal.
|
||||
|
||||
Mainly `SIGCONT`.
|
||||
Mainly `SIGCONT`.
|
||||
|
||||
POSIX specific signals include:
|
||||
POSIX specific signals include:
|
||||
|
||||
- SIGKILL
|
||||
# SIGKILL
|
||||
|
||||
Kills program.
|
||||
Kills program.
|
||||
|
||||
Cannot be handled unlike to `SIGINT` and `SIGTERM`.
|
||||
Cannot be handled unlike to `SIGINT` and `SIGTERM`.
|
||||
|
||||
- SIGQUIT
|
||||
# SIGQUIT
|
||||
|
||||
Quit program.
|
||||
Quit program.
|
||||
|
||||
Used in case of abnormal termination (`A`), unlike `SIGINT` and `SIGTERM` which happen on normal temrination.
|
||||
Used in case of abnormal termination (`A`), unlike `SIGINT` and `SIGTERM` which happen on normal temrination.
|
||||
|
||||
May generate a core dump <https://en.wikipedia.org/wiki/Core_dump> depending on system configurations.
|
||||
May generate a core dump https://en.wikipedia.org/wiki/Core_dump depending on system configurations.
|
||||
|
||||
On Ubuntu, coredumps are disabled by default. You can enable them for the current session with:
|
||||
On Ubuntu, coredumps are disabled by default. You can enable them for the current session with:
|
||||
|
||||
ulimit -c unlimited
|
||||
ulimit -c unlimited
|
||||
|
||||
on the terminal where you will run the command to enable core dumps.
|
||||
on the terminal where you will run the command to enable core dumps.
|
||||
|
||||
The setting can be permanently changed on the `/etc/security/limits.conf` file.
|
||||
The setting can be permanently changed on the `/etc/security/limits.conf` file.
|
||||
|
||||
The core file is binary. To interpret it you must have compiled the program with debugging
|
||||
information and then use GDB on the core file and the executable as:
|
||||
The core file is binary. To interpret it you must have compiled the program with debugging
|
||||
information and then use GDB on the core file and the executable as:
|
||||
|
||||
gcc -g -o myfile myfile.c
|
||||
gdb myfile core
|
||||
gcc -g -o myfile myfile.c
|
||||
gdb myfile core
|
||||
|
||||
- SIGSTOP
|
||||
# SIGSTOP
|
||||
|
||||
Freezes program.
|
||||
Freezes program.
|
||||
|
||||
`ctrl+z`, in linux terminals.
|
||||
`ctrl+z`, in linux terminals.
|
||||
|
||||
Cannot be handle.
|
||||
Cannot be handle.
|
||||
|
||||
- SIGCONT
|
||||
# SIGCONT
|
||||
|
||||
Continues a process that
|
||||
Continues a process that
|
||||
|
||||
- SIGHUP
|
||||
# SIGHUP
|
||||
|
||||
Controlling terminal was killed.
|
||||
Controlling terminal was killed.
|
||||
|
||||
This is why killing the terminal kills most process by default unless those process implement a handler.
|
||||
This is why killing the terminal kills most process by default unless those process implement a handler.
|
||||
|
||||
- SIGPIPE
|
||||
# SIGPIPE
|
||||
|
||||
Process write to a pipe with no readers on other side
|
||||
Process write to a pipe with no readers on other side
|
||||
|
||||
- SIGCHLD
|
||||
# SIGCHLD
|
||||
|
||||
Child terminated, stopped or continued.
|
||||
Child terminated, stopped or continued.
|
||||
|
||||
Ignored by default.
|
||||
Ignored by default.
|
||||
|
||||
- SIGALRM
|
||||
# SIGALRM
|
||||
|
||||
Received after the alarm call after given no of secs.
|
||||
Received after the alarm call after given no of secs.
|
||||
|
||||
- SIGUSR1 and SIGUSR2: left to users to do whatever they want with
|
||||
# SIGUSR1
|
||||
|
||||
#Parent death signal
|
||||
# SIGUSR2
|
||||
|
||||
In POSIX, no signal needs to be sent to the child if the parent exits:
|
||||
<http://stackoverflow.com/questions/284325/how-to-make-child-process-die-after-parent-exits>
|
||||
In Linux, this can be achieved via the `prctl` syscall.
|
||||
This may seem surprising considering that:
|
||||
Left to users to do whatever they want with. Default to `term`.
|
||||
|
||||
- parents can wait for children
|
||||
# Parent death signal
|
||||
|
||||
- children get a NOHUP when controling process is killed
|
||||
This is mentioned at: <http://pubs.opengroup.org/onlinepubs/009695399/functions/exit.html>
|
||||
In POSIX, no signal needs to be sent to the child if the parent exits:
|
||||
http://stackoverflow.com/questions/284325/how-to-make-child-process-die-after-parent-exits
|
||||
In Linux, this can be achieved via the `prctl` syscall.
|
||||
This may seem surprising considering that:
|
||||
|
||||
TODO what is a controlling process?
|
||||
- parents can wait for children
|
||||
|
||||
#sources
|
||||
- children get a NOHUP when controling process is killed
|
||||
This is mentioned at: http://pubs.opengroup.org/onlinepubs/009695399/functions/exit.html
|
||||
|
||||
- <http://www.alexonlinux.com/signal-handling-in-linux>
|
||||
TODO what is a controlling process?
|
||||
|
||||
good intro
|
||||
# Sources
|
||||
|
||||
- man 7 signal
|
||||
- `man 7 signal`
|
||||
|
||||
man pages
|
||||
man pages
|
||||
|
||||
# TODO
|
||||
- http://www.alexonlinux.com/signal-handling-in-linux
|
||||
|
||||
- determine where specification barriers betwwen ANSIC / POSIX / linux
|
||||
good intro
|
||||
|
||||
# TODO
|
||||
|
||||
- determine where specification barriers betwwen ANSIC / POSIX / linux
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
@ -175,28 +179,36 @@ POSIX specific signals include:
|
||||
#include <unistd.h>
|
||||
|
||||
void signal_handler(int sig) {
|
||||
// The `sig` arg allows us to use a single function for several different signals:
|
||||
// just look at it and decide which action to take based on the signal number.
|
||||
/*
|
||||
The `sig` arg allows us to use a single function for several different signals:
|
||||
just look at it and decide which action to take based on the signal number.
|
||||
*/
|
||||
|
||||
printf("sig: %d\n", sig);
|
||||
|
||||
// After the signal is dealt with, the handler is then changed to its default action
|
||||
// If you want to continue using this handler for future signals, you have to reregister
|
||||
// it here: TODO confirm. If I remove this it does not work.
|
||||
/*
|
||||
After the signal is dealt with, the handler is then changed to its default action
|
||||
|
||||
signal(sig, signal_handler);
|
||||
If you want to continue using this handler for future signals, you have to reregister
|
||||
it here: TODO confirm. If I remove this it does not work.
|
||||
*/
|
||||
|
||||
// You can change the action handler at any time
|
||||
// For example, if you uncomment this line, only the first signal will be ignored
|
||||
// and but the second will be dealt with the default action:
|
||||
/*signal(sig, signal_handler);*/
|
||||
|
||||
//(void) signal( sig, SIG_DFL );
|
||||
/*
|
||||
You can change the action handler at any time
|
||||
|
||||
For example, if you uncomment this line, only the first signal will be ignored
|
||||
and but the second will be dealt with the default action:
|
||||
*/
|
||||
|
||||
/*(void) signal( sig, SIG_DFL );*/
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
/*
|
||||
#signal
|
||||
# signal
|
||||
|
||||
POSIX recommends `sigaction` instead of `signal`.
|
||||
*/
|
||||
@ -204,7 +216,7 @@ int main() {
|
||||
signal(SIGALRM, signal_handler);
|
||||
|
||||
/*
|
||||
#Send signal
|
||||
# Send signal
|
||||
|
||||
This is done via the kill function:
|
||||
|
||||
@ -217,7 +229,7 @@ int main() {
|
||||
TODO 0 which? same uid?
|
||||
*/
|
||||
|
||||
//send a SIGINT to ourselves:
|
||||
/* send a SIGINT to ourselves: */
|
||||
assert(kill(getpid(), SIGALRM) == 0);
|
||||
|
||||
int i = 0;
|
||||
@ -234,7 +246,7 @@ int main() {
|
||||
}
|
||||
|
||||
/*
|
||||
#pause
|
||||
# pause
|
||||
|
||||
Stop program until it receives a signal.
|
||||
*/
|
||||
|
196
signal.c
196
signal.c
@ -1,91 +1,123 @@
|
||||
/*
|
||||
signals are a simple way for processes to communicate
|
||||
Signals are a simple way for processes to communicate.
|
||||
|
||||
signals are limited to passing a single byte between two processes
|
||||
Signals are limited to passing a single byte between two processes.
|
||||
|
||||
what almost each signal does is all predefined by ansi c
|
||||
What almost each signal does is all predefined by ANSI C
|
||||
or specific operating systems
|
||||
|
||||
# example: control c
|
||||
# Example: control + c
|
||||
|
||||
an example most linux people have used directly already:
|
||||
hit ctrl+c in a terminal and this will send an INT signal
|
||||
to the running process.
|
||||
An example most Linux people have used directly already:
|
||||
hit Ctrl + C in a terminal and this will send an INT signal
|
||||
to the running process.
|
||||
|
||||
Unless the process implements a handler for this process,
|
||||
this has the effect of destroying the process,
|
||||
which is what happens by default for most, but not all signals.
|
||||
Unless the process implements a handler for this process,
|
||||
this has the effect of destroying the process,
|
||||
which is what happens by default for most, but not all signals.
|
||||
|
||||
# ansi c
|
||||
# ANSI C
|
||||
|
||||
there is a small C ANSI signal interface,
|
||||
and individual operating systems may implement many more
|
||||
which is the case for linux
|
||||
There is a small ANSI C signal interface,
|
||||
and individual operating systems may implement many more
|
||||
which is the case for Linux.
|
||||
|
||||
6 signals defined:
|
||||
6 signals defined:
|
||||
|
||||
- SIGABRT: (Abort) Abnormal termination, such as is initiated by the abort function.
|
||||
# SIGABRT
|
||||
|
||||
- SIGFPE: (Floating-Point Exception) Erroneous arithmetic operation.
|
||||
Abort.
|
||||
|
||||
Such as zero divide or an operation resulting in overflow
|
||||
Abnormal termination, such as is initiated by the `abort` function.
|
||||
|
||||
Not necessarily generated by a floating-point operation, may be an integer operation.
|
||||
# SIGFPE
|
||||
|
||||
floating point division by 0 `1.0 / 0.0` does not generate exceptoins since it is defined by IEEE:
|
||||
<http://stackoverflow.com/questions/7267838/division-by-zero-does-not-throw-sigfpe>
|
||||
Floating-Point Exception.
|
||||
|
||||
integer division by 1 / 0 may generate a SIGFPE
|
||||
Erroneous arithmetic operation such as division by zero divide
|
||||
or an operation resulting in overflow.
|
||||
|
||||
TODO is 1 / 0 guaranteed to generate a `SIGFPE`?
|
||||
Unlike the name suggests, it is not necessarily generated by a floating-point operation:
|
||||
it may also happen on an integer operation.
|
||||
|
||||
TODO how to deal with it? it just keeps coming back time after time.
|
||||
Floating point division by 0 `1.0 / 0.0` does not generate exceptoins since it is defined by IEEE:
|
||||
<http://stackoverflow.com/questions/7267838/division-by-zero-does-not-throw-sigfpe>
|
||||
|
||||
very similar question, but his behaviour is not exactly the same as mine:
|
||||
<http://stackoverflow.com/questions/14905947/what-does-c-c-handler-sigfpe>
|
||||
Integer division by 1 / 0 may generate a `SIGFPE`.
|
||||
|
||||
TODO is 1 / 0 guaranteed to generate a `SIGFPE`?
|
||||
|
||||
- SIGILL: (Illegal Instruction) Things that can generate this on Linux x86:
|
||||
TODO how to deal with it? it just keeps coming back time after time.
|
||||
|
||||
- making an assembly operation that is only legal from kernel mode on user mode,
|
||||
such as modify cs, ds or ss registers from a user program.
|
||||
Very similar question, but his behaviour is not exactly the same as mine:
|
||||
http://stackoverflow.com/questions/14905947/what-does-c-c-handler-sigfpe
|
||||
|
||||
- SIGSEGV: (Segmentation Violation)
|
||||
# SIGILL
|
||||
|
||||
Invalid access to storage: When a program tries to read or write outside the memory it has allocated.
|
||||
Illegal Instruction.
|
||||
|
||||
- SIGINT: (Interrupt) Ask the process to terminate, possibly nicely. Sample cause: linux terminal ctrl+c.
|
||||
Things that can generate this on Linux x86:
|
||||
|
||||
- SIGTERM: (Terminate) Termination request sent to program. Major cause: shutdown, window close.
|
||||
- making an assembly operation that is only legal from kernel mode on user mode,
|
||||
such as modify cs, ds or ss registers from a user program.
|
||||
|
||||
The only difference between `SIGINT` and `SIGTERM` is that `SIGINT` is meant to be generated manually by users
|
||||
from the terminal, while `SIGTERM` is meant to be generated by other applications.
|
||||
# SIGSEGV
|
||||
|
||||
Functions defined (handlers):
|
||||
Segmentation Violation.
|
||||
|
||||
- SIG_DFL Default handling: The signal is handled by the default action for that particular signal.
|
||||
- SIG_IGN Ignore Signal: The signal is ignored.
|
||||
- SIG_ERR Special return value indicating failure.
|
||||
Invalid access to storage: When a program tries to read or write
|
||||
outside on an address and the OS does not like it because it is using too much memory.
|
||||
|
||||
#raise
|
||||
# SIGINT
|
||||
|
||||
TODO
|
||||
Interrupt
|
||||
|
||||
#abort
|
||||
Ask the process to terminate, possibly nicely.
|
||||
|
||||
TODO
|
||||
Sample cause: Linux terminal Ctrl + C.
|
||||
|
||||
#allows opeartions on signal handlers
|
||||
# SIGTERM
|
||||
|
||||
TODO can any operation be done in a signal handler (print to stdout for example?)
|
||||
Terminate.
|
||||
|
||||
#sig_atomic_t
|
||||
Termination request sent to program. Major cause: shutdown, window close.
|
||||
|
||||
TODO
|
||||
The only difference between `SIGINT` and `SIGTERM` is that `SIGINT` is meant to be generated manually by users
|
||||
from the terminal, while `SIGTERM` is meant to be generated by other applications.
|
||||
|
||||
# sources
|
||||
Functions defined (handlers):
|
||||
|
||||
- <http://www.alexonlinux.com/signal-handling-in-linux>
|
||||
# SIG_DFL
|
||||
|
||||
Default handling: The signal is handled by the default action for that particular signal.
|
||||
|
||||
# SIG_IGN
|
||||
|
||||
Ignore Signal: The signal is ignored.
|
||||
|
||||
# SIG_ERR
|
||||
|
||||
Special return value indicating failure.
|
||||
|
||||
# raise
|
||||
|
||||
TODO
|
||||
|
||||
# abort
|
||||
|
||||
TODO
|
||||
|
||||
# Allowed opeartions on signal handlers
|
||||
|
||||
TODO can any operation be done in a signal handler (print to stdout for example?)
|
||||
|
||||
# sig_atomic_t
|
||||
|
||||
TODO
|
||||
|
||||
# Sources
|
||||
|
||||
- http://www.alexonlinux.com/signal-handling-in-linux
|
||||
|
||||
good intro, covers lots of POSIX / linux specific stuff,
|
||||
but also has nice examples that help understand the ANSI C model.
|
||||
@ -95,28 +127,36 @@ TODO
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void signal_handler( int sig )
|
||||
{
|
||||
//sig arg allows us to use a single function for several different signals:
|
||||
//just look at it and decide which action to take based on the signal number
|
||||
void signal_handler(int sig) {
|
||||
/*
|
||||
Signal arguments allow us to use a single function for several different signals:
|
||||
just look at it and decide which action to take based on the signal number
|
||||
*/
|
||||
|
||||
//printf( "sig: %d\n", sig );
|
||||
/*printf("sig: %d\n", sig);*/
|
||||
|
||||
//after the signal is dealt with, the handler is then changed to its default action
|
||||
//if you want to continue using this handler for future signals, you have to reregister
|
||||
//it here: TODO confirm. If I remove this it does not work.
|
||||
/*
|
||||
After the signal is dealt with, the handler is then changed to its default action
|
||||
|
||||
signal( sig, signal_handler );
|
||||
if you want to continue using this handler for future signals, you have to reregister
|
||||
it here: TODO confirm. If I remove this it does not work.
|
||||
*/
|
||||
|
||||
//you can change the action handler at any time
|
||||
//for example, if you uncomment this line, only the first signal will be ignored
|
||||
//and but the second will be dealt with the default action:
|
||||
signal(sig, signal_handler);
|
||||
|
||||
//(void) signal( sig, SIG_DFL );
|
||||
/*
|
||||
You can change the action handler at any time.
|
||||
|
||||
For example, if you uncomment this line, only the first signal will be ignored.
|
||||
|
||||
And but the second will be dealt with the default action:
|
||||
*/
|
||||
{
|
||||
/*(void) signal(sig, SIG_DFL);*/
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int main() {
|
||||
/*
|
||||
registers signal_handler as handler for SIGINT and SIGTERM:
|
||||
|
||||
@ -128,23 +168,25 @@ int main()
|
||||
- opening a new termianal (ex: `xterm` on linux)
|
||||
- running this program on that terminal
|
||||
|
||||
from the current terminal, and then closing the first terminal.
|
||||
From the current terminal, and then closing the first terminal.
|
||||
*/
|
||||
|
||||
signal( SIGINT, signal_handler );
|
||||
signal( SIGTERM, signal_handler );
|
||||
signal( SIGFPE, signal_handler );
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGFPE, signal_handler);
|
||||
|
||||
//#floating point exception
|
||||
//# Floating point exception
|
||||
|
||||
//{
|
||||
// int i = 0;
|
||||
// int j = 0;
|
||||
// //cannot do 1 / 0 or the compiler will give a warning. Lets dupe him:
|
||||
// j = 1 / i;
|
||||
// //you need this `printf` or the compiler may optimize your division away
|
||||
// printf( "%d", j );
|
||||
//}
|
||||
/*
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
//cannot do 1 / 0 or the compiler will give a warning. Lets dupe him:
|
||||
j = 1 / i;
|
||||
//you need this `printf` or the compiler may optimize your division away
|
||||
printf( "%d", j );
|
||||
}
|
||||
*/
|
||||
|
||||
//int i = 0;
|
||||
//while ( i < 10 )
|
||||
|
Loading…
x
Reference in New Issue
Block a user