Common methods and techniques in C language

  • 2020-05-17 06:07:44
  • OfStack

C language commonly used methods and techniques

The division is rounded up

#define DIV_ROUND_UP(n, d) (((n)+(d)-1) / (d))

Large end small end selection

low-endian or high-endian


typedef union {
 short W; /* Word access */
 struct { /* Byte access */
#ifdef LOW_ENDIAN
 byte low, high; /* in low-endian arch */
#else
 byte high, low; /* in high-endian arch */
#endif
 } B;
} word;

Remainder operations


a = a % 8;
=>
a = a & 7;

Note: bit operation only needs 1 instruction cycle; Taking a remainder usually requires calling a subroutine.

Square arithmetic


a = pow(a, 2.0);
=>
a = a * a;

Note: in the processor with built-in multiplication unit, multiplication operation is faster than square operation; Multiplication subroutines are more efficient than square operators, even without a built-in multiplication unit.

Shift implements multiplication and division


a = a * 4;
b = b / 4;
=>
a = a << 2;
b = b >> 2;

Note: usually multiply or divide by 2n, but use the shift method instead.


a = a * 9;
=>
a = (a << 3) + a;

while loops and do... while cycle

Description: do... The compiled code generated by the while loop is shorter than that generated by the while loop.

Redefine types to extend portability


typedef unsigned char  boolean; /* Boolean value type. */
typedef unsigned long int uint32; /* Unsigned 32 bit value */
typedef unsigned short  uint16; /* Unsigned 16 bit value */
typedef unsigned char  uint8; /* Unsigned 8 bit value */
typedef signed long int  int32; /* Signed 32 bit value */
typedef signed short  int16; /* Signed 16 bit value */
typedef signed char   int8; /* Signed 8 bit value */

Gets a byte or word at the specified address


typedef unsigned char byte; /* Unsigned 8 bit value type */ 
typedef unsigned short word; /* Unsigned 16 bit value type */

#define MEM_B(x) (*((byte*)(x)))
#define MEM_W(x) (*((word*)(x)))

To calculate the extremum


#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))

Get an offset of field in the structure (struct)


typedef unsigned long dword; /* Unsigned 32 bit value type */

#define FPOS(type, field)\
 ( (dword)&((type*)0)->field )

Gets the number of bytes consumed by field in a structure


#define FSIZE(type, field)\
 ( sizeof(((type*)0)->field) )

Convert 1 word(16 bit) to 2 bytes in LSB format


a = a % 8;
=>
a = a & 7;
0

I get the address of one variable


typedef unsigned char byte; /* Unsigned 8 bit value type */
typedef unsigned short word; /* Unsigned 16 bit value type */ 

#define B_PTR(var) ((byte*)(void*)&(var))
#define W_PTR(var) ((word*)(void*)&(var))

You get the low and high bits of 1 byte


typedef unsigned char byte; /* Unsigned 8 bit value type */
typedef unsigned short word; /* Unsigned 16 bit value type */

#define WORD_L(var) ((byte)(word)(var)&(0xFF))
#define WORD_H(var) ((byte)(word)(var)>>(8))

Returns a multiple approaching 8 larger than X

#define RND8(x) ((((x) + 7) >> 3) << 3)

Ways to prevent spills


a = a % 8;
=>
a = a & 7;
3

Returns the number of elements in an array


a = a % 8;
=>
a = a & 7;
4

Returns the last n digit of an unsigned number


a = a % 8;
=>
a = a & 7;
5

The IO space maps the structure in the storage space


a = a % 8;
=>
a = a & 7;
6

The use of "#" and "##" in macros

1. Use "#" to change the macro parameter to 1 string, and use "##" to match the macro parameter to 1.


 #define STR(val) (#val)
 #define CONS(a, b) (int)(a##e##b)
 ->
 STR(hello) ==> "hello"
 CONS(2, 3) ==> 2000 // 2e3

2. When the macro parameter is another macro

Note that macros are no longer expanded where '#' or '##' is useful in the macro definition.

1, not '#' and '##'


  #define TOW   (2)
  #define MUL(a,b) (a*b)

  printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW));
  ==>
  printf("%d*%d=%d\n", (2), (2), ((2)*(2)));

The parameter TOW in MUL will be expanded to (2).

2. When there is '#' or '##'


a = a % 8;
=>
a = a & 7;
9

INT_MAX and A will not be expanded, however, the solution to this problem is very simple, add one more layer of intermediate conversion macro, the purpose of adding this layer of macro is to expand all macro parameters in this layer, so that the 1 macro (_STR) in the conversion macro will get the correct macro parameters.


  #define A   (2)   
  #define _STR(s)  (#s)
  #define STR(s)  _STR(s)  //  Conversion macros 
  #define _CONS(a,b) int(a##e##b)
  #define CONS(a,b) _CONS(a,b) //  Conversion macros 

  printf("int max: %s\n", STR(INT_MAX)); // INT_MAX,int The maximum value of type is 1 A variable  #include

The output is: int max: 0x7fffffff


  STR(INT_MAX) --> _STR(0x7fffffff)  And then convert it to a string ;
  printf("%d\n", CONS(A, A));

The output is: 200

  CONS(A, A) --> _CONS((2), (2)) --> int((2)e(2))

3. Some special cases of '#' and '##'

1. Merge anonymous variable names


  #define ___ANONYMOUS1(type, var, line) type var##line
  #define __ANONYMOUS0(type, line)  ___ANONYMOUS1(type, _anonymous, line)
  #define ANONYMOUS(type)     __ANONYMOUS0(type, __LINE__)

Example: ANONYMOUS (static int);

static int _anonymous70; 70 represents the bank number;

Level 1: ANONYMOUS(static int);
-- > __ANONYMOUS0(static int, __LINE__);

Level 2: -- > ___ANONYMOUS1(static int, _anonymous, 70);

Level 3: -- > static int _anonymous70;

That is, only the macros of the current layer can be untied at a time, so s 162en__ can be untied at the 2nd layer.

2. Filling structure


  #define FILL(a)  {a, #a}
  enum IDD {OPEN, CLOSE};
  typedef struct MSG{
   IDD id;
   const char * msg;
  }MSG;

  MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};
  ==>
  MSG _msg[] = {{OPEN, "OPEN"},

  {CLOSE, "CLOSE"}};

3. Record file name


  #define _GET_FILE_NAME(f) #f
  #define GET_FILE_NAME(f) _GET_FILE_NAME(f)

  static char FILE_NAME[]  = GET_FILE_NAME(__FILE__);

4. Get the string buffer size corresponding to a numeric type


  #define _TYPE_BUF_SIZE(type) sizeof #type
  #define TYPE_BUF_SIZE(type)  _TYPE_BUF_SIZE(type) 

  char buf[TYPE_BUF_SIZE(INT_MAX)]; 
  --> char buf[_TYPE_BUF_SIZE(0x7fffffff)]; 
  --> char buf[sizeof "0x7fffffff"]; 

This is equivalent to: char buf[11];


Related articles: