【notes】一些编程方法



1. 使用位移运算,逻辑与或运算优化逻辑运算


(1). 对 2^n 次方取余运算,通过&运算得到n-1到0次和,即余数值

int ret = x % 8;
int ret = x & 7; // 即 x & 0x0111

(2). * / 计算,使用<< >> 等提高效率

  1. 2 ^ n 中n为2的整数倍,如x * 16,即x * 2 ^ 4 ,
int ret = x * 16;
int ret = x << 4; // 2 ^ 4 = 16
  1. 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标准库并不支持,解决方式两种。

  1. 添加头文件:
#include <stdbool.h>
  1. 按照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类型数据。

实例:略


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过得精彩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值