c/c++编程小知识

1、拆分字节

1.1、全部拆分

一个字节可以拆分成 8 个 bit,下面的方法拆分出的字节储存在 m 数组里,data 是要拆分的字节。

int jk(int data){
int m[8];
int i;
for(i=0; i < 8; i++)
    {
        m[i]=data & 0x01;
        data = data >> 1;
    }
return 0;
}

具体效果是,4 会被拆分成 00100000,并储存在 m 数组里。简单来说就,就是将 4 转换成二进制数。不同于 c/c++ 自带的函数,这个方法是把 4 拆分成单个 bit 保存下来,而自带的函数则会把 4 转换成一个二进制字符串。4 的二进制表示是 00000100,而这个方法拆分得到的数据和原来比较是相反的,也就是 00000100 会变成 00100000。

1.2、部分拆分

这个方法是拆分出特定位置的数字。

unsigned int a = 0x12345678;
((x >>  0) & 0x000000ff);/* 获取第 0 个字节,结果是 0x78 */
((x >>  8) & 0x000000ff);/* 获取第 1 个字节,结果是 0x56 */
((x >> 16) & 0x000000ff);/* 获取第 2 个字节,结果是 0x34 */
((x >> 24) & 0x000000ff);/* 获取第 3 个字节,结果是 0x12 */
((0b101 >> 2) & 0x01);/* 获取第 2 个字节,结果是 0x34 */

假设要把 a 按字节拆分。两位数字占了 8 个 bit,取第 n 个字节,就右移 8n 个 bit,然后和 0xff 按位与,就可以得出结果。0xff 不是随便取的,8 个 bit 最大的数字是 255(十进制),换成十六进制就是 ff。

同理,把 a 按单个数字拆分,一位数字占了 4 个 bit,取第 n 个字节,就右移 4n 个 bit,然后和 0x1111 按位与。把数字换成二进制,自己手动运算一下就知道原理了。

2、c/c++ 内存知识

现代操作系统对每个进程都分配了完整的虚拟内存地址空间。进程会把整个地址空间分成多个区间来使用。

c_c++内存分布.webp

图片来源: http://www.sw-at.com/blog/2011/03/23/where-does-code-execute-process-address-space-code-gvar-bss-heap-stack/

虚拟内存技术使得每个进程都可以“独占”整个内存空间,地址从零开始,直到内存用完。 每个进程都将这部分空间(从低地址到高地址)分为六个部分:

  1. TEXT 段:程序的代码,以及常量。这部分内存固定大小,只读的。对常量的赋值将产生 segment fault 错误。
  2. DATA 段:又称 GVAR,初始化为非零的全局变量。
  3. BSS 段:初始化为 0 或未初始化的全局变量和静态变量。可以认为 BSS 段中的所有字节都是 0。它们都会被初始化为 0,同时类的成员变量也会被初始化为 0,但编译器不保证局部变量的初始化。
  4. HEAP(堆空间):动态内存区域,使用 malloc 或 new 申请的内存。
  5. 未使用的内存。
  6. STACK(栈空间):局部变量、参数、返回值都存在这里,函数调用开始会参数入栈,局部变量入栈,调用结束后,按照先进后出的顺序出栈。

堆空间和栈空间的大小是可变的。堆空间从下往上生长,栈空间从上往下生长。(这句话不一定正确,要看操作系统如何实现内存管理)

栈(STACK)是从上到下(高地址到低地址)分配的,函数的局部变量的空间是在进入函数体后才分配的。

上述和CPU端模式也有关系!小端字节序的,低位存的是低字节。大端字节序的,低位存的是高字节。

变量所占内存的回收方式取决于该变量的存储类型(storage class)。

  1. 局部变量,存储在栈空间内。它占用的空间会在函数调用结束后自行释放,如果调用太多次,栈来不及释放,会造成内存溢出。
  2. 全局变量,存储在 DATA 段或者 BSS 段,它的空间是始终存在的,直至程序结束运行。
  3. 如果是 new 或者 malloc 得到的空间,它存储在 HEAP(堆)中,除非手动 delete 或 free,否则空间会一直占用直至进程结束。

参考文章:

https://blog.csdn.net/xtuwz/article/details/79532770

https://harttle.land/2015/07/22/memory-segment.html

https://harttle.land/2015/07/22/memory-segment.html

3、提高 c/c++ 效率的方法

下面是运算效率对比。

移位 > 赋值 > 大小比较 > 加法 > 减法 > 乘法 > 取模 > 除法

  1. 尽量用移位操作代替其他操作,编译器会帮我们优化,这个一点并不必要,还是要看具体情况。
  2. 尽量用指针运算代替数组索引,产生的代码往往又快又短。与数组索引相比,指针能使代码更快,占用更少。使用多维数组时差异更明显。
  3. 使用或设置尽量小的数据类型,这样使生成的代码的数量减少很多,执行速度提高。
  4. 如果说数据量有限,可以采用查表的方式,执行速度会快一些。
  5. 要充分利用 CPU 的指令缓存,就要充分分解小的循环。循环很小时,可以拆分。
  6. 按数据类型的长度排序,长的在前,短的在后。把结构体填充成最长类型长度的整倍数。
  7. 尽量用自减替代自加,内存占用会少一点。
  8. 使用 do while 循环编译后生成的代码的长度短于 while 循环。
  9. 循环少嵌套。
  10. Switch 语句中根据发生频率来进行 case 排序,频率高的在前。
  11. 有分支的语句也保持频率高的在前。
  12. 大批量内存拷贝,用 memcpy 代替赋值语句

4、杂项

  1. 当数据不均匀,而又对数据十分敏感的时候,映射是一个好办法。例如触控板绝对模式发送的绝对位置,映射处理之后,更加均匀并且可以减少错误数据的影响。
  2. a^b=b^a
    a^(b^c)=(a^b)^c
    a^b^b=a
    余数定理,(ab)%c=(a%c)(b%c)%c
  3. 结论:byte、short、char 做混合运算的时候,各种先转换成 int 再做运算。
  4. 期望是概率的倒数
  5. 两个数的最小公倍数可以代替原来的两个数。最小公倍数的两个数为 x 和 y,他们的最大公约数为 p,最小公倍数为 q。则 xy=pq

c_c++几何划分.webp

更新日志

2022/7/25:提高效率部分补充些内容。

暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇