C/C++ knowledge collection
# pointer & const

Key point: The * is the seperator. The right side is declarator, *p is a pointer, *const p is a const pointer. The left side is the specifiers, is type. const T and T const are same.
(1) = (2), p pointer point to const T, p can be changed. T cannot be changed.
(4) = (5), const p pointer point to const T, p and T cannot be changed.
(3), const p pointer point to T, T can be changed. p cannot be changed.
The storage specifiers like static or exter are for p. example, static const T *p.
/** * The size of a ring buffer. * Due to the design only <tt> RING_BUFFER_SIZE-1 </tt> items * can be contained in the buffer. * The buffer size must be a power of two. */ #define RING_BUFFER_SIZE 128 /** * Used as a modulo operator * as <tt> a % b = (a & (b − 1)) </tt> * where \c a is a positive index in the buffer and * \c b is the (power of two) size of the buffer. */ #define RING_BUFFER_MASK (RING_BUFFER_SIZE-1)
#log printf with default information
#include <stdio.h> #ifdef DEBUG #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\ __FILE__, __LINE__, ##__VA_ARGS__) #else #define log_info(M, ...) #endif int main(int argc, char *argv[]) { log_info("Start of program"); int var = 10; printf("my variable is %d\n", var); log_info("End of program"); }
#Syntax modification
it is very powerful usage of Macro. example, foreach
#include <stdio.h> struct ListNode; typedef struct ListNode { struct ListNode *next; struct ListNode *prev; void *value; } ListNode; typedef struct List { int count; ListNode *first; ListNode *last; } List; #define LIST_FOREACH(curr, list) \ ListNode *curr = list->first;\ for (ListNode *_node = list->first; \ _node != NULL; \ curr = _node = _node->next) int main(int argc, char *argv[]) { List *lst; /* Fill the linked list */ LIST_FOREACH(curr, lst) { printf("%d\n", (int)curr->value); } }
#using Macro for default argument
#include <stdio.h> #define printErrord(errorCode) printError(errorCode, "No message") void printError(int errorCode, char *msg) { printf("Error code: %d (%s)\n", errorCode, msg); } int main(int argc, char *argv[]) { printError(9, "Bad alloc"); printErrord(8); }
#GCC warning: will be initialized after -wreorder
#do {} while (0)
it is a coding idiom to support multi-lines in Macro.
C++ version
/* The macro is defined in "DEBUG" project options */ #ifdef TARGET_DEBUG #define SYSTEM_ASSERT(s) do {string str(__FILE__);\ str.erase(0, str.find_last_of("\\/") + 1);\ printf("%20s:%04d ", str.c_str(), __LINE__);\ printf(s);\ NVIC_SystemReset();\ } while (0); #define SYSTEM_INFO(s) do {string str(__FILE__);\ str.erase(0, str.find_last_of("\\/") + 1);\ printf("%20s:%04d ", str.c_str(), __LINE__);\ printf(s);\ }while(0) #else #define SYSTEM_ASSERT(s) do {NVIC_SystemReset();} while(0); #define SYSTEM_INFO(s) #endif
#log
The log information is very useful whenever debug or mass production. here it is an example with release or debug control, also support runtime version
#include <syslog.h> #include <stdlib.h> #include <stdio.h> #include "LogInterface.h" //=============================DEBUG MESSAGE LEVEL============================== #define DMSG_EMERG 0X80 //system can not be used #define DMSG_ALERT 0X40 //need take immediate action #define DMSG_CRIT 0x20 //critical situation, such as hard disk failure #define DMSG_ERR 0X10 //error condition #define DMSG_WARNING 0X08 //warning condition #define DMSG_NOTICE 0X04 //normal and important message #define DMSG_INF 0X02 //ordinary message #define DMSG_DEBUG 0X01 //debug or trace output #define DMSG_NONE 0X00 //close the MSG function! #define DMSG_ALL 0XFF //let all MSG level message can be printed /* here log can be configured in runtime */ #ifdef DYNAMICAL_LOG_LEVEL #define LOG_LEVEL g_print extern unsigned char g_print; #else #ifndef LOG_LEVEL #define LOG_LEVEL DMSG_NONE #endif #endif //================================DPRINT======================================== #ifdef RELEASE #define DPRINT(level, fmt, args...) \ if(level&(DMSG_EMERG|DMSG_ALERT|DMSG_CRIT|DMSG_ERR))\ {\ Log_Print(fmt, ##args);\ } #else #define DPRINT(level, fmt, args...) \ if(level&(DMSG_EMERG|DMSG_ALERT|DMSG_CRIT|DMSG_ERR))\ {\ Log_Print(fmt, ##args);\ }\ if((LOG_LEVEL)&(level))\ {\ printf(fmt, ##args);\ } #endif //================DPRINT with function name and line number===================== #ifdef RELEASE #define DFLPRINT(level, fmt, args...) #else #define DFLPRINT(level, fmt, args...) if(LOG_LEVEL&(level)) {printf("Function: %s, Line: %d, ", \ __FUNCTION__, __LINE__); printf(fmt, ##args);} #endif
# extern c
extern "C" makes a function-name in C++ have 'C' linkage (compiler does not mangle the name) so that client C code can link to (i.e use) your function using a 'C' compatible header file that contains just the declaration of your function.
#ifdef __cplusplus extern “C” { #endif #ifdef __cplusplus } #endif
sometimes, we use g++ to compile the C code for safety consideration.
# type covert
For pointer, example, unsigned char* to char* or const unsigned char* to unsigned char*
using reinterpret_cast <target type> (value)
For covert between enum or uint8_t, we can use static_cast<>
#parsing arguments
#include <getopt.h>
function name is getopt_long()
#stand I/O
in linux, there are some default file descriptors, 0 for stdin, 1 for stdout, and 2 for stderr.
stdout is buffered, Data written to stdout is not sent to the console(or other device, if it’s redirected) until the buffer fills. using fflush(stdout) to force send out
stderr is not buffered; data written to stderr goes directly to the console
#return value
Return non-zero means there is error in linux.
#environment variables
Both environment variable names and their values are character strings.
common environment variables, e.g. $USER, $HOME, $PATH
e.g. echo $HOME, will print your home path
using export command to set the variable, e.g. export MY_VAR=abc
in c, using getenv, setenv unsetenv to get/set/clear the value, the header file is <stdlib.h>
environ is the global varaible to store the system envionment variables, don't modify it directly.
char* server_name = getenv (“SERVER_NAME”); if (server_name == NULL) { server_name = “xxxx”; }
#system specific code
#ifdef _WIN32 #include <windows.h> #include <stdio.h> #include <tchar.h> #define DIV 1048576 #define WIDTH 7 #endif #ifdef __linux__ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #endif
| Operating System | Macro present | Notes |
|---|---|---|
| Windows 32 bit + 64 bit | _WIN32 |
for all Windows OS |
| Windows 64 bit | _WIN64 |
Only for 64 bit Windows |
| Apple | __APPLE__ |
for all Apple OS |
| Apple | __MACH__ |
alternative to above |
| iOS embedded | TARGET_OS_EMBEDDED |
include TargetConditionals.h |
| iOS stimulator | TARGET_IPHONE_SIMULATOR |
include TargetConditionals.h |
| iPhone | TARGET_OS_IPHONE |
include TargetConditionals.h |
| MacOS | TARGET_OS_MAC |
include TargetConditionals.h |
| Android | __ANDROID__ |
subset of linux |
| Unix based OS | __unix__ |
|
| Linux | __linux__ |
subset of unix |
| POSIX based | _POSIX_VERSION |
Windows with Cygwin |
| Solaris | __sun |
|
| HP UX | __hpux |
|
| BSD | BSD |
all BSD flavors |
| DragonFly BSD | __DragonFly__ |
|
| FreeBSD | __FreeBSD__ |
|
| NetBSD | __NetBSD__ |
|
| OpenBSD | __OpenBSD__ |
#using temp file
Before using temp file, we shall know that the application can be executed more than one instance. at the same time, we shall consider the file permission, otherwsie the hacker may use the weakness to attack it.
Linux provides a method to create a temp unique file by mkstemp. the file cannot be removed automatically, so you can use unlink after created, in that, the file will be removed if the reference count is zero. The file can be removed event your program crash.
example code as below.
/* Create the filename and file. The XXXXXX will be replaced with characters that make the filename unique. */ char temp_filename[] = “/tmp/temp_file.XXXXXX”; int fd = mkstemp (temp_filename); /* Unlink the file immediately, so that it will be removed when the file descriptor is closed. */ unlink (temp_filename);
Keil ouptut memory information
Code代表执行的代码,程序中所有的函数都位于此处。
RO-data代表只读数据,程序中所定义的全局常量数据和字符串都位于此处。
RW-data代表已初始化的读写数据,程序中定义并且初始化的全局变量和静态变量位于此处。
ZI-data 代表未初始化的读写数据,程序中定义了但没有初始化的全局变量和静态变量位于此处。
Good reference
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define container_of(ptr, type, member) \ ((type *) ((char *) (ptr) - offsetof(type, member))) #define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v) #define UV_STRINGIFY_HELPER(v) #v #define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \ UV_STRINGIFY(UV_VERSION_MINOR) "." \ UV_STRINGIFY(UV_VERSION_PATCH) unsigned int uv_version(void) { return UV_VERSION_HEX; } const char* uv_version_string(void) { return UV_VERSION_STRING; }
#define offsetof(s,m) ((size_t)&(((s*)0)->m))
浙公网安备 33010602011771号