风过空庭,字句正徐来。
关于关于本站关于我给我点钱
更多时间线友链文件服务wiki
联系写留言发邮件GitHub
© 2024-2026 yono. | RSS 订阅 | 站点地图 | | Stay hungry. Stay foolish.
Powered by Mix Space&
白い
.
| 粤 ICP 备2024284785号-1 |
正在被0人看爆
且听风定,再看句成。
残片纸堆

strlen 小品一则

w72w
AI·GEN

关键洞察

strlen 小品一则

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • 计算字符串长度还在一个字节一个字节比对 0x00?

    据说 glibc 是这样的 strlen 实现,一次性判断例如4个字节(32位),看其中是否存在 0x00,再仔细查找。

    例如我们是32位的寄存器,那么可以一次查找4个字节。

    uint32_t no_zero_byte(uint32_t v)
    {
        const uint32_t himagic = 0x80808080;
        const uint32_t lomagic = 0x01010101;
    
        return ((v - lomagic) & ~v & himagic);
    }
    

    这是啥玩意?因为0x00-0x01会产生借位,而借位后的值是0xFF,与0x00取反相同,围绕这个点展开计算。

    首先字符串是连续的字节地址,那么可以直接当作32位值进行读取,记作 v。

    然后若某个字节是0x00,那么当个字节减去0x01应当会发生借位,也就是 (v - lomagic) 。使用 & ~v 可以判断是否发生了借位。

    如果是超出最高位的借位,那么是0xFF,则使用 & himagic 再判断。

    假设理解不了那么结合这个实例

    如果现在判断到的字符串4字节是 {0x11, 0x22, 0x33, 0x00}

    那么直接取址转换 v 是 0x00332211

    v - 0x01010101 = 0xFF322110
    
    ~v = 0xFFCCDDEE
    
    (v - 0x01010101) & ~v = 0xFF000100     // 意味着发生了借位
    
    FF000100 & 0x80808080 = 0x80000000 // 意为着发生了超出最高位的借位,也就是找到了0x00的位置,是第4个字节
    

    如果现在判断到的字符串4字节是 {0x11, 0x22, 0x33, 0x44}

    那么直接取址转换 v 是 0x44332211

    v - 0x01010101 = 0x43322110
    
    ~v  = 0xBBCCDDEE
    
    (v - 0x01010101) & ~v =  0x03000100
    

    优势

    某些芯片中,类似 if(v == 0x00) 这样的判断非常耗时,使用这样单纯的位计算得值则可以避免这个问题。