Skip to content

Instantly share code, notes, and snippets.

@BimManager
Last active February 20, 2023 21:24
Show Gist options
  • Select an option

  • Save BimManager/e85a6297b58f717083c0a19c3396e3b2 to your computer and use it in GitHub Desktop.

Select an option

Save BimManager/e85a6297b58f717083c0a19c3396e3b2 to your computer and use it in GitHub Desktop.
C
<=SEARCH PATH=>
// to find the default search directory list
cpp -v /dev/null -o /dev/null
#define "foo.h" => in relative to the directory of the current file
#define <foo.h> => in a preconfigured list of standard system directories
cpp -I/path/to/headers -iquote/path/to/quoted_headers -isystem/path/to/angle_bracketed_headers
cpp -nostdinc
<=MACROS=>
Object-like macros & Function-like macros
#define NAME REPLACEMENT_TEXT
#define BUFFER 1024
#define TEXT(quote) L##quote
#define FOREVER for(;;) // an infinite loop
#define MAX(A, B) ((A>B) ? (A) : (B)) // expands into inline code;
// will serve for any data type; The expression is evaluated twice.
#undef MAX // undefined to ensure that a routine is really a function, not a macro
#define SWAP(T, A, B) { T temp = A; \
A = B; \
B = temp; }
// Include Guard macro
// https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Include_Guard_Macro
#ifndef MYHEADER_H_ // beginning
#define MYHEADER_H_
// ...
#endif // MYHEADER_H_ // end
<=TYPEDEF=>
typedef unsigned short wchar_t;
typedef int MY_INT;
typedef char* PCHAR;
typedef void* PVOID;
typedef void (*FOO) (const char*, int); // FOO is a function pointer type
// ^ ^ ^
// return_type type_name arguments
typedef struct {float x; float y; char* name;} POINT;
int main(int argc, char** argv) {
MY_INT i = 10; // equivalent to int i = 10;
PCHAR pch = nullptr; // equivalent to char* pch = nullptr;
FOO pfn; // equivalent to void (*pfn)(const char*, int);
POINT* pPnt = malloc(sizeof(POINT));
pPnt
return 0;
}
<=BUFFER=>
Buffer is an area of memory set aside for storage of data.
Buffer is a region of a physical memory storage used to store data temporarily while being moved from one place to another.
TCHAR szBuffer[MAX_PATH];
// a buffer that may hold as many tchar characters as MAX_PATH
<=POINTERS=>
Dynamic memory allocation
// On 64-bit systems every memory address is 64-bit long, totalling 8 bytes
char* pch = nullptr;
int* pi = 0;
void* pv = malloc(sizeof(char)); // a pointer to an unknown type
if(pv != NULL) {
// code block
void* pv = realloc(5 * sizeof(char)); // reallocate memory
free(pv);
pv = NULL; // set the pointer to null
}
char c = 'a';
pch = &c; // the address-of operator
printf("c=%c", *c); // the dereference operator
printf("pch=%p", pch);
<=POINTER DECLARATION IN C/C++=>
#define BUFFER 1024
// POINTERS TO OBJECTS
struct _Foo { int n; } SFoo, *pSFoo;
int i = rand();
int* pi = &i;
int* const* pkpi = &i;
// a non-const pointer to a const pointer to a non-const int
int* pn = &pSFoo->n;
int rgi[BUFFER];
int* const kprgi = rgi; // a const pointer to an array of int
// POINTERS TO VOID
int iFoo = 100;
int* piFoo = &iFoo;
void* pv = piFoo;
std::cout << *static_cast<*int>(pv);
<h3>POINTERS TO FUNCTIONS</h3>
void baz(int);
void (*pfnbaz)(int) = &baz; // & is optional
// The ``Clockwise/Spiral Rule''
There is a technique known as the ``Clockwise/Spiral Rule'' which enables any C programmer to parse in their head any C declaration!
There are three simple steps to follow:
Starting with the unknown element, move in a spiral/clockwise direction; when ecountering the following elements replace them with the corresponding english statements:
* [X] or [] => Array X size of... or Array undefined size of...
* (type1, type2) => function passing type1 and type2 returning...
* * => pointer(s) to...
Keep doing this in a spiral/clockwise direction until all tokens have been covered.
Always resolve anything in parenthesis first!
Example #1: Simple declaration
+-------+
| +-+ |
| ^ | |
char *str[10];
^ ^ | |
| +---+ |
+-----------+
Question we ask ourselves: What is str?
``str is an...
We move in a spiral clockwise direction starting with `str' and the first character we see is a `[' so, that means we have an array, so...
``str is an array 10 of...
Continue in a spiral clockwise direction, and the next thing we encounter is the `*' so, that means we have pointers, so...
``str is an array 10 of pointers to...
Continue in a spiral direction and we see the end of the line (the `;'), so keep going and we get to the type `char', so...
``str is an array 10 of pointers to char''
We have now ``visited'' every token; therefore we are done!
Example #2: Pointer to Function declaration
+--------------------+
| +---+ |
| |+-+| |
| |^ || |
char *(*fp)( int, float *);
^ ^ ^ || |
| | +--+| |
| +-----+ |
+------------------------+
Question we ask ourselves: What is fp?
``fp is a...
Moving in a spiral clockwise direction, the first thing we see is a `)'; therefore, fp is inside parenthesis, so we continue the spiral inside the parenthesis and the next character seen is the `*', so...
``fp is a pointer to...
We are now out of the parenthesis and continuing in a spiral clockwise direction, we see the `('; therefore, we have a function, so...
``fp is a pointer to a function passing an int and a pointer to float returning...
Continuing in a spiral fashion, we then see the `*' character, so...
``fp is a pointer to a function passing an int and a pointer to float returning a pointer to...
Continuing in a spiral fashion we see the `;', but we haven't visited all tokens, so we continue and finally get to the type `char', so...
``fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char''
Example #3: The ``Ultimate''
+-----------------------------+
| +---+ |
| +---+ |+-+| |
| ^ | |^ || |
void (*signal(int, void (*fp)(int)))(int);
^ ^ | ^ ^ || |
| +------+ | +--+| |
| +--------+ |
+----------------------------------+
Question we ask ourselves: What is `signal'?
Notice that signal is inside parenthesis, so we must resolve this first!
Moving in a clockwise direction we see `(' so we have...
``signal is a function passing an int and a...
Hmmm, we can use this same rule on `fp', so... What is fp? fp is also inside parenthesis so continuing we see an `*', so...
fp is a pointer to...
Continue in a spiral clockwise direction and we get to `(', so...
``fp is a pointer to a function passing int returning...''
Now we continue out of the function parenthesis and we see void, so...
``fp is a pointer to a function passing int returning nothing (void)''
We have finished with fp so let's catch up with `signal', we now have...
``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning...
We are still inside parenthesis so the next character seen is a `*', so...
``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to...
We have now resolved the items within parenthesis, so continuing clockwise, we then see another `(', so...
``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning...
Finally we continue and the only thing left is the word `void', so the final complete definition for signal is:
``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning nothing (void)''
The same rule is applied for const and volatile. For Example:
const char *chptr;
Now, what is chptr??
``chptr is a pointer to a char constant''
How about this one:
char * const chptr;
Now, what is chptr??
``chptr is a constant pointer to char''
Finally:
volatile char * const chptr;
Now, what is chptr??
``chptr is a constant pointer to a char volatile.''
Practice this rule with the examples found in K&R II on page 122.
// Copyright 2021 kkozlov
// gcc -pthread concurrency.c
// static storage class if data is used only within the file
// extern storage class if data is used by other files
#include <unistd.h> // sleep(seconds)
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
return EXIT_SUCCESS;
}
// Detaching a thread indicates to the system that its resources can
// be reclaimed when it is finished.
pthread_t pthread_self(void);
int pthread_create(pthread_t *thread, pthread_attr_t const *attr,
void *(start *)(void *), void *arg);
int pthread_join(pthread_t thread, void **value_ptr);
int pthread_detach(pthread_t thread);
int pthread_equal(pthread_t t1, pthread_t t2);
int pthread_exit(void *value_ptr);
int sched_yield(void);
// ready => running => blocked => terminated
// a thread becomes blocked in the following cases:
// 1. it attempts to lock a mutex that is currently locked
// 2. it waits on a conditional variable
// 3. it calls sigwait for a signal that is not currently pending
// 4. it attempts an I/O operation that cannot be immediately completed
// 5. for other system operations such as a page fault
// SYNCHRONIZATION
// MUTEXES
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_init(pthread_mutex_t *mutex,
pthread_mutexattr_t *metuxattr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex); // blocking function
int pthread_mutex_trylock(pthread_mutex_t *mutex); // nonblocking func
// EBUSY == status
int pthread_mutex_unlock(pthread_mutex_t *mutex);
// How to prevent deadlocks
// Fixed locking hierarchy
// (always unlock mutexes in the reverse order of locking)
// Try and back off
// CONDITION VARIABLES
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond,
pthread_condattr_t *condattr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex,
struct timespec *expiration);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
// Waiting on a condition variable releases the associated mutex
// and awaits until another thread signals (to wake one waiter) or
// broadcast (to wake all waiters) the condition variable.
// Condition variables are for signalling not for mutual exclusion.
// Condition variables and predicates go hand in hand.
// When a thread waits on a condition variable, it must always
// have the associated mutex locked.
// THE CONDITION VARIABLE WAIT OPERATION WILL UNLOCK THE MUTEX
// BEFORE BLOCKING THE THREAD AND IT WILL RELOCK THE MUTEX
// BEFORE RETURNING TO YOUR CODE.
// When a waiting thread awakens, it must first lock the mutex.
// It is paramount to test the predicate after locking the appropriate mutex
// and before waiting on the condition variable.
// ALWAYS WAIT FOR A CONDITION VARIABLE IN A WHILE LOOP TESTING
// THE PREDICATE.
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int value;
} lock_t;
lock_t lock = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER,
0
};
void *wait_thread(void *data) {
int status = pthread_mutex_lock(&lock.mutex);
if (status != 0) err_abort(status, "Lock mutex");
lock.value = 1; // set the predicate
status = pthread_cond_signal(&lock.cond);
if (status != 0) err_abort(status, "Signal condition");
status = pthread_mutex_unlock(&lock.mutex);
if (status != 0) err_abort(status, "Unlock mutex");
return NULL;
}
int main(void) {
pthread_t wait_thread_it;
int status = pthread_create(&wait_thread_id, NULL, wait_thread, NULL);
if (status != 0) err_abort(status, "Create wait thread");
status = pthread_mutex_lock(&lock.mutex);
if (status != 0) err_abort(status, "Lock mutex");
while (0 == lock.value) { // to tackle supirous wakeups
status = pthread_cond_wait(&cond, NULL);
if (status != 0) err_abort(status, "Wait on codition");
}
status = pthread_mutex_unlock(&mutex);
}
/*
** how to pass a 2d array to a function
*/
#define M 42
#define N 42
/* a static array */
void assign(int arr[][N]);
void assign(int m, int n, int arr[m][n]);
/* an array of pointers */
void assign(int **arr, int m, int n);
/* a 1d array */
/* static array */
void assign(int m, int n, int *arr); /* arr[i * n + j] */
/* a dynamic array */
void assign(int *arr, int m, int n);
Logically, every program comprises three primary parts - namely @interface, @implementation, and program.
// syntax of applying methods to classes or instances
[ ClassOrInstance method ];
// @interface syntax
@interface ClassName : ParentClassName
{
memberDeclarations;
}
methodDeclarations;
@end
// @implementation syntax
@implementation ClassName
methodDefinitations;
@end
- (void) set_numerator : (int) n;
| | | | | |
method return method method arg arg
type type name takes args type name
// program syntax
#import <Foundation/Foundation.h>
@interface Fraction : NSObject
{
int m_num;
int m_den;
}
@property int numerator, denominator;
- (void) setTo : (int) n : over (int) d; // multi-argument method
- (void) print;
- (Fraction *) add : (Fraction *) f;
@end
@implementation
@synthesize numerator, denominator;
- (void) setTo : (int) n : over (int) d
{
m_num = n;
m_den = d;
}
- (void) print
{
// ...
}
- (Fraction *) add : (Fraction *) f
{
// ...
}
@end
int main(void)
{
NSAutoreleasePool *pool;
Fraction *f;
pool = [[NSAutoreleasePool alloc] init];
f = [[Fraction alloc] init];
[f setTo : 100 over 200 ];
[f release];
[pool drain];
}
// self keyword
[self reduce]
// designated init method definition
- (id) initWithValue : (int) val // designated initialiser
{
if (self = [super init])
{
[self setValue: val];
}
return (self);
}
// overridden init
- (id) init
{
self = [self initWithValue: 0];
return (self);
}
// dealloc method
- (void) dealloc
{
if (otherResources)
[otherResources release];
[super dealloc];
}
// external variables
// foo.c
int g_counter; // defined in a source file outside any function or method
// and NOT preceded by the extern keyword
// g_counter is an external global variable
static int g_watcher; // this definition makes the variable global but only accessible from the source file in which it has been defined. (its scope is restricted to the implementation file)
// bar.c
void increment_global_var()
{
extern int g_counter; // the keyword extern means declaration not definition
++g_counter;
}
// A global variable may be declared many times (using the extern keyword), yet it must be defined only once.
// The best approach in terms of memory management
- (void)setName:(NSString *)name
{
fullName = [[NSString alloc] initWithString: name]; // copy of the argument
}
// The worst approach in terms of memory management
- (void)setName:(NSString *)name{
fullName = name; // a reference to the actual string object
}
- (void)setName:(NSString *)name
{
fullName = [NSString stringWithString: name]; // this object will be autoreleased by the NSString class
}
// The description method
- (NSString *)description
{
return ([NSString stringWithFormat(@"\nFull Name: %@\nEmail: %@", fullName, email)]);
}
<=C FOLDER STRUCTURE=>
project
.gitignore
Makefile
bin/
build/
doc/
include/
lib/
src/
test/
the tools of the trade
the content of the binutils package:
addr2line (converts addresses into filenames and line numbers)
ar (creates, modifies and extracts file archives)
as (assembles assembly language code into object code)
c++filt (filter to demangle c++ symbols)
gprof (a program to display program profiling information)
ld (a linker to convert objet code files into executable files)
nlmconv (converts object code into Netware Loadable Module format)
nm (lists symbols from object files)
objcopy (copies and translates object files)
objdump (displays information from object files)
ranlib (generates an index to the contents of an archive file)
readelf (dispalys information from an object file in ELF format)
size (lists the section sizes of an object or archive file)
strace (traces system calls and signals)
strings (displays printable strings found in object files)
strip (discard symbols)
windres (compiles Microsoft Windows resource files)
gdb (lldb)
valgrind
ctags
doxygen
lxr
#define LEN 10
int const LEN = 10;
#define _STR(x) _VAL(x)
#define _VAL(x) #x
printf("## debug info\n");
(void)p;
#ifdef UNDEF /* 0 */
/* instead of commenting out a section of code */
#endif /* UNDEF */
#define NULL (void *)0
#ifndef NDEBUG
#endif
keywords
static
volatile
const
* A visible function occupies a separate source file
* A secret name begins with an underscore followed by an uppercase letter (_Getint)
* Secret functions reside in a file beginning with x (xgetint.c)
* Test files start with t (tassert.c, tstdout1.c, tstdou2.c)
void f(char const *param); /* const after the type */
suffixes: _ptr, _p, _pp, _fd, _file, _max, _min, _cnt, _key
prefixes: n_
standard short names
pointers: p, q
character: c
counter: n
string: s
abbreviations
avg (average)
aux (auxiliary)
buf (buffer)
cfg (configuration)
curr (current)
err (error)
init (initialize)
io (input/output)
max (maximum)
mgr (manager)
min (minimum)
msg (message)
num (number of)
reg (register)
q (queue)
sem (semaphore)
sync (synchronize)
str (string (null terminated))
temp (temperature)
tmp (temporary)
use:
<stdint.h>
<stdbool.h>
bool b_in_motion = (0 != speed_in_mph);
No procedure shall have a name that begins with an underscore
No procedure name shall be longer than 31 characters
No function name shall contain any uppercase letters
No macro shall contain any lowercase letters
Underscores shall be used to separate words in procedure names
"noun-verb" word ordering is recommended (e.g., abc_read(), led_is_on())
The names of all public funcions shall be prefixed
with their module name and an underscore (e.g., sensor_read())
No variable name shall be shorter than 3 characters, including loop counters
g_zero_offer // a global variable
p_led_reg // a pointer to led_reg
pp_vector_table // a pointer to a pointer to ...
b_done_yet or b_is_buffer_full // a boolean variable
[g][p|pp][b|h]
It is a preferred practice to place the shortest of if and else if clauses first
Any if statement with an else if shall end with an else clause
Assingments shall not be made within an if or else if test.
if (NULL == p_object)
// Do not use this ...
#define MAX(A, B) ((A) > (B) ? (A) : (B))
// ... when you can do this instead
inline int max(int num1, int num2);
All functions that encapsulate threads of execution shall be
given names ending with "_thread" (or "_taks", "_process")
void alarm_thread(void *data_p);
// Struct declaration
struct name_tag
{
type1 member1;
type2 member2;
};
typedef name_tag
{
type1 member1;
type2 member2;
} struct_alias;
// Struct initialization
struct point
{
int x;
int y;
};
struct point p = { 42, 42 };
struct point q = { .x = 42, .y = 42 }; // C99-style
struct t = q; // copy member values from q into t
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment