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. 

 

#modulo operator
 
/**
 * 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

 
class a
{
private:
int ma;
int mb;
public:
a(int ia, ib) : mb(ib), ma(ia) {};
}
 
solution: Make sure the members appear in the initializer list in the same order as they appear in the class

 

 #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 SystemMacro presentNotes
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))

 

 

posted on 2019-11-08 11:08  荷树栋  阅读(240)  评论(0)    收藏  举报

导航