初始化函数的开始, 可以用一个static变量作为标志, 保证功能只被初始化一次. 如:

void avcodec_init(void)
    {
        static int initialized = 0;
        if (initialized != 0)
        {
            return;
        }
        initialized = 1;
        //真正的初始化代码
        dsputil_static_init();
    }

递归与循环在编程模型和思维模型上最大的区别在于:
  循环是在描述我们该如何地去解决问题.
  递归是在描述这个问题的定义.

宏中使用do{…} while(0)来保证安全性

辗转相除求最大公约数:

//其中a大于b
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

或者如下:

while(a%=b^=a^=b^=a);

判断一个数是否为2的次幂:

return (!(x & (x-1)));

假设n为正数, 可以使用

return ((n & -n) == n);

或者:

bool ifPowerOfTwo = ((x!=0)&&((~x+1)&x==x));

Isolates last non zero digit of a’s binary representation.

a -= (a & -a);

找出二进制数中1的个数:

def countBits(n): #runs in O(log m) time where m is number of bits in n
    count=0
    while n:
        n = n & (n - 1)
        count = count + 1
    return count

将浮点型空间用memset初始化为-1, 可以使用如下代码判断变量是否被再次改变:

if (ret == ret)
    return ret;

原因在于-1在浮点型被识别为NaN, 不等于任何数, 甚至不等于自身.

计算一个二进制数中1的数量:

for(c=0; v; ++c)
        v &= v - 1;

交换a和b的值:

a = a + b - (b = a); //可能有错且效率低下

或:

a ^= b;
b ^= a;
a ^= b;
//等价于以下,该方法在a与b地址相同时会出错
a ^= b ^= a ^= b;

雷神之锤3中平方根倒数算法:

float FastInvSqrt(float x)
{
    float xhalf = 0.5f * x;
    int i = *(int*)&x;          // evil floating point bit level hacking
    i = 0x5f3759df - (i >> 1);  // what the fuck?
    x = *(float*)&i;
    x = x*(1.5f-(xhalf*x*x));
    return x;
}

二分查找:

int lo = 0, hi = N;
    for(int mid = (lo + hi)/2; hi - lo > 1; mid = (lo + hi)/2)
        (arr[mid] > x? hi : lo) = mid;
    return lo;
    // assuming N < 2^30, else "(hi + lo)" may overflow int
    // can be worked around using lo + (hi-lo)/2 : see answer-comment thread

整数乘法:

public static int multiply (int a, int b)
{
    return b==0?0:((b&1) ==1?a:0)+multiply(a<<1,b>>1);
}

预编译与文件的使用技巧:

double normals[][] =
{
    #include "normals.txt"
};

找出比n大的最小的2的次幂:

inline int elegant(int n)
{
    n+=(n==0);
    n--;
    n|=n>>1;
    n|=n>>2;
    n|=n>>4;
    n|=n>>8;
    n=n>>16;
    n++;
    return n;
}

结构体末尾使用长度为0的数组, 便于扩展, 比如用malloc给结构体分配空间, 加上一段长度作为扩展的数据.

使用__COUNTER__宏来计数
使用__DATE__ TIME FILE LINE func

使用 while(!scanf()) 来遇到EOF时结束读取

使用offsetof宏来获取结构体成员偏移量

#include <stdio.h>
    #include <stdlib.h>
    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    //定义结构体和结构体变量
    struct abc
    {
        int a;
        int b[4];
        int c;
    } abc_inst;
    //打印偏移量
    int main()
    {
        printf ("%lu %lu %lu\n", offsetof(struct abc, a), 
                            offsetof(struct abc, b), 
                            offsetof(struct abc, c));
        return 0;
    }

scanf的高级用法:
http://blog.csdn.net/wesweeky/article/details/6439777

结构体中bit的使用:

struct
    {
        int    a:3;
        int    b:2;
        int     :0;
        int    c:4;
        int    d:3;
    };

which will give a layout of

000aaabb 0ccccddd instead of without the :0;

0000aaab bccccddd The 0 width field tells that the following bitfields should be set on the next atomic entity (char)

使用 ` #pragma message() ` 向编译信息窗口输出信息 使用 ` #error … ` 中断编译

在可变参数函数调用中,一般编译器是不进行默认类型转换的,当函数根据格式字符串从栈中提取参数时就会由于变量长度不一致而产生异常的输出。

单行注释中的末尾换行符可能导致bug, 如下:

//将文件a.log保存到目录: C:\
SaveFile(file, "C:\\a.log");

以下代码有异曲同工之妙:

float result = num/*pInt; 
/*  some comments */
-x<10 ? f(result):f(-result);

”??! is a trigraph that translates to | .” 所以可以用”??!”代替”|”使用, 可能起到迷惑作用. 这实际上是C语言为老式键盘设计的特性,称之为“三字母词”(trigraph)。

trigraph sequencessymbol
??=#
??([
??/\
??)\
??'^
??<{
??!|
??>}
??-~

sizeof()是一个编译时的运算符, 不会对括号内的表达式进行求值.

将数组单独定义为结构体, 可以在参数传递时按值传递. 如下:

struct ABC
{
    char array[100];
}abc;

在C语言中, 大括号仅仅作为”命名空间”的作用, 并没有”堆栈边界”的作用.

Look up the access() function. You can replace your function with

if( access( fname, F_OK ) != -1 )
{
    // file exists
}
else
{
    // file doesn't exist
}

You can also use R_OK, W_OK, and X_OK in place of F_OK to check for read permission, write permission, and execute permission (respectively) rather than existence, and you can OR any of them together (i.e. check for both read and write permission using R_OK|W_OK)
Update: Note that on Windows, you can’t use W_OK to reliably test for write permission, since the access function does not take DACLs into account. access( fname, W_OK ) may return 0 (success) because the file does not have the read-only attribute set, but you still may not have permission to write to the file.

使用三目运算符?:对const变量进行初始化:

const int bytesPerPixel = isAlpha() ? 4 : 3;

使用 ` do{…} while(0); ` 可以在循环体中用break代替goto语句.

可以用宏实现(不通过传地址而改变变量的值)的功能.

函数回调的机制允许了底层代码调用在高层定义的功能. 例如, 库可以调用使用者定义的功能.

不使用判断和循环, 打印1-1000的所有数字:

#include "stdio.h"
    #include "stdlib.h"
    //强制使用函数地址进行运算
    int main(int j)
    {
        printf( "%d\n", j);
        (( int (*)(int ))((int)&main + (( int)&exit - (int )&main)*(j/1000)))(j + 1);
        return 0;
    }

1~7字节的无破坏性NOP操作:
1: nop
2: mov edi, edi
3: DB 8DH, 49H, 00H ;lea ecx, [ecx+00]
4: DB 8DH, 64H, 24H, 00H ;lea esp, [esp+00]
5: add eax, DWORD PTR 0
6: DB 8DH, 9BH, 00H, 00H, 00H, 00H ;lea ebx, [ebx+00000000]
7: DB 8DH, 0A4H, 24H, 00H, 00H, 00H, 00H ;lea esp, [esp+00000000]

使用&&可以取出label的地址. (gcc特性)

C语言的{}代码块是有值的, 值为最后一个表达式的值.

Numbers Everyone Should Know from Google

trigraph sequencestime
L1 cache reference0.5ns
Branch mispredict5ns
L2 cache reference7ns
Mutex lock/unlock25ns
Main memory reference100ns
Compress 1K bytes with Zippy10,000ns
Send 2K bytes over 1 Gbps network20,000ns
Read 1 MB sequentially from memory250,000ns
Round trip within same datacenter500,000ns
Read 1 MB sequentially from memory1,000,000ns
Disk seek10,000,000
Read 1 MB sequentially from network10,000,000
Read 1 MB sequentially from disk30,000,000
Send packet CA->Netherlands->CA150,000,000

使用_alloca函数可以在栈上分配内存,以实现变长数组之类的应用。

Post Info


Published

13 January 2014

Category

Program

Tags