文章目录
1. 使用位移运算,逻辑与或运算优化逻辑运算
(1). 对 2^n 次方取余运算,通过&运算得到n-1到0次和,即余数值
int ret = x % 8;
int ret = x & 7; // 即 x & 0x0111
(2). * / 计算,使用<< >> 等提高效率
- 2 ^ n 中n为2的整数倍,如x * 16,即x * 2 ^ 4 ,
int ret = x * 16;
int ret = x << 4; // 2 ^ 4 = 16
- 2 ^ n 中n非2的整数倍,如 x * 15 ,即 x * 2 ^ 4 - x
PS: 乘数数值与2对应权重位为1的数值相差大于1的乘数不建议使用,因为会使用一次* / 计算,违背了初衷。
int ret = x * 15;
int ret = (x<<4) - x ; // 15 = 2 ^ 4 - 1 , 如果这里是 * 13 ,则需要一次额外乘法运算,违背设计初衷
2. 各类数据的比较
(1). float类型数据与绝对零值做比较
浮点数无法在非模拟计算机中被准确比较
如下是精度为0.000001的比较方法,经供参考
if (x>0.000001&&x<-0.000001) {}
3. linux C
(1). bool类型在不在linuxC标准库中
由于“没有消息就是最好的消息”的原理,linux中以return 0;代表执行成功。
虽然false 和 true被明确标注为关键字,但linuxC标准库并不支持,解决方式两种。
- 添加头文件:
#include <stdbool.h>
- 按照linuxC的编程思想,将true用0代替。
(2). strlcpy 等 BSD库函数
strlcpy()与strncpy() strcpy()函数类似
区别是strlcpy()可以避免dst存储空间不够的陷阱。比如dst长度为5,src长度为10,则strlcpy后,
dst的实际存储为xxxx\0,即当dst长度不够时,在最后加入’\0’
strlcpy() 属于BSD库函数,没有被glibc收录,所有默认情况下glibc无法使用。
如果linux下要使用,需要添加libbsd
(3). unlikely() 、likely() 优化分支预测逻辑
在编译时用于控制分支预测结果,提高分支预测命中率,提高分支预测效率
将linkely()后的程序优先存放,避免来回jump
头文件
<linux/compiler.h>
, 原型:unlikely() likely()
int i;
/* likely() */
for (i = 0; i < 8; i++){
if(likely(i % 8)) /* 1,2,3,4,5,6,7 */
printk("i % 8 != 0\n");
else /* 0 */
printk("i % 8 == 0\n");
}
/* unlikely() */
for (i = 0; i < 8; i++){
if(unlikely(i == 4))/* 4 */
printk("i == 4\n");
else /* 0,1,2,3,5,6,7 */
printk("i != 4\n");
}
4. 各类attr属性
(1) attribute((weak,alias(“XXXX”)))
weak : 弱符号,如果其他地方有实现,则默认先链接强符号的实现函数
alias : 起别名,为一个现有的函数提供一个其他的名字,如保持库函数接口不变
测试源码 :
/* func.h */
#ifndef __FUNC_H__
#define __FUNC_H__
void func_a1(void);
void func_a2(void);
void func_a3(void);
#endif
/* func.c */
#include <stdio.h>
void func(void);
void func(void)
{
printf("%s: %s\n",__FILE__, __func__);
}
void func_a1(void) __attribute__((weak,alias("func")));
void func_a2(void) __attribute__((weak,alias("func")));
/* TEST_WEAK */
void func_a3(void) __attribute__((weak,alias("func")));
/* main.c */
#include <stdio.h>
#include "func.h"
#define TEST_WEAK
#ifdef TEST_WEAK
void func_a3(void)
{
printf("%s: %s\n", __FILE__, __func__);
}
#endif
int main(int argc, char **argv)
{
func_a1();
func_a2();
func_a3();
return 0;
}
# Makefile
CC := gcc
src := $(shell ls *.c)
objs := $(patsubst %.c,%.o,$(src))
.PHONY : all
all : test
test : $(objs)
$(CC) -o $@ $^
%.o : %.c
$(CC) -o $@ -c $<
.PHONY : clean
clean:
rm -f $(objs) test
log :
# make
gcc -o func.o -c func.c
gcc -o main.o -c main.c
gcc -o test func.o main.o
# ./test
func.c: func
func.c: func
main.c: func_a3
(2) attribute((aligned (X)))
为了让数据对齐,减少cpu的读取频率,提高系统效率
缺点是会占用更多的存储空间,
比如:32bit系统,存储1个char,1个int,从0x0000开始存储
char占用1个字节,int占用4个字节,则分布如下:
32bit 第一个周期
0x0000:char
0x0001:int
0x0002:int
0x0003:int
…
0x0004: int
0x0005:N/A这样的环境下读取这个int数据,就需要先读取0x0001~0x0003,再读取0x0004。
如果使用该属性4字节对齐的方式存储这个int,那么4*8=32bit,int存储起始位置就是32整数倍,
这样读取内存只需要一次即可全部读取32bit数据,即一次即可完全读取这个int类型数据。
实例:略