[strlen的GNU实现]有趣的代码

本文介绍了一种通过位操作加速字符串长度计算的方法。该方法利用特定的位掩码和加法运算来快速检测字符串中的空终止符,从而显著提高strlen函数的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先搁这吧,晚上回去分析。
  1. #include<string.h>
  2. #include<stdlib.h>
  3. #undefstrlen
  4. /*
  5. Returnthelengthofthenull-terminatedstringSTR.Scanfor
  6. thenullterminatorquicklybytestingfourbytesatatime.
  7. */
  8. size_tstrlen(str)
  9. constchar*str;
  10. {
  11. constchar*char_ptr;
  12. constunsignedlongint*longword_ptr;
  13. unsignedlongintlongword,magic_bits,himagic,lomagic;
  14. /*
  15. Handlethefirstfewcharactersbyreadingonecharacteratatime.
  16. DothisuntilCHAR_PTRisalignedonalongwordboundary.
  17. */
  18. for(char_ptr=str;((unsignedlongint)char_ptr
  19. &(sizeof(longword)-1))!=0;++char_ptr)
  20. if(*char_ptr=='/0')
  21. returnchar_ptr-str;
  22. /*
  23. Alltheseelucidatorycommentsreferto4-bytelongwords,
  24. butthetheoryappliesequallywellto8-bytelongwords.
  25. */
  26. longword_ptr=(unsignedlongint*)char_ptr;
  27. /*
  28. Bits31,24,16,and8ofthisnumberarezero.Callthesebits
  29. the"holes."Notethatthereisaholejusttotheleftof
  30. eachbyte,withanextraattheend:
  31. bits:01111110111111101111111011111111
  32. bytes:AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
  33. The1-bitsmakesurethatcarriespropagatetothenext0-bit.
  34. The0-bitsprovideholesforcarriestofallinto.
  35. */
  36. magic_bits=0x7efefeffL;
  37. himagic=0x80808080L;
  38. lomagic=0x01010101L;
  39. if(sizeof(longword)>4)
  40. {
  41. /*64-bitversionofthemagic.*/
  42. /*Dotheshiftintwostepstoavoidawarningiflonghas32bits.*/
  43. magic_bits=((0x7efefefeL<<16)<<16)|0xfefefeffL;
  44. himagic=((himagic<<16)<<16)|himagic;
  45. lomagic=((lomagic<<16)<<16)|lomagic;
  46. }
  47. if(sizeof(longword)>8)
  48. abort();
  49. /*
  50. Insteadofthetraditionalloopwhichtestseachcharacter,
  51. wewilltestalongwordatatime.Thetrickypartistesting
  52. if*anyofthefour*bytesinthelongwordinquestionarezero.
  53. */
  54. for(;;)
  55. {
  56. /*WetentativelyexittheloopifaddingMAGIC_BITSto
  57. LONGWORDfailstochangeanyoftheholebitsofLONGWORD.
  58. 1)Isthissafe?Willitcatchallthezerobytes?
  59. Supposethereisabytewithallzeros.Anycarrybits
  60. propagatingfromitsleftwillfallintotheholeatits
  61. leastsignificantbitandstop.Sincetherewillbeno
  62. carryfromitsmostsignificantbit,theLSBofthe
  63. bytetotheleftwillbeunchanged,andthezerowillbe
  64. detected.
  65. 2)Isthisworthwhile?Willitignoreeverythingexcept
  66. zerobytes?SupposeeverybyteofLONGWORDhasabitset
  67. somewhere.Therewillbeacarryintobit8.Ifbit8
  68. isset,thiswillcarryintobit16.Ifbit8isclear,
  69. oneofbits9-15mustbeset,sotherewillbeacarry
  70. intobit16.Similarly,therewillbeacarryintobit
  71. 24.Ifoneofbits24-30isset,therewillbeacarry
  72. intobit31,soalloftheholebitswillbechanged.
  73. Theonemisfireoccurswhenbits24-30areclearandbit
  74. 31isset;inthiscase,theholeatbit31isnot
  75. changed.Ifwehadaccesstotheprocessorcarryflag,
  76. wecouldclosethisloopholebyputtingthefourthhole
  77. atbit32!
  78. Soitignoreseverythingexcept128's,whenthey'realigned
  79. properly.*/
  80. longword=*longword_ptr++;
  81. if(
  82. #if0
  83. /*AddMAGIC_BITStoLONGWORD.*/
  84. (((longword+magic_bits)
  85. /*Setthosebitsthatwereunchangedbytheaddition.*/
  86. ^~longword)
  87. /*Lookatonlytheholebits.Ifanyoftheholebits
  88. areunchanged,mostlikelyoneofthebyteswasa
  89. zero.*/
  90. &~magic_bits)
  91. #else
  92. ((longword-lomagic)&himagic)
  93. #endif
  94. !=0)
  95. {
  96. /*
  97. Whichofthebyteswasthezero?Ifnoneofthemwere,itwas
  98. amisfire;continuethesearch.
  99. */
  100. constchar*cp=(constchar*)(longword_ptr-1);
  101. if(cp[0]==0)
  102. returncp-str;
  103. if(cp[1]==0)
  104. returncp-str+1;
  105. if(cp[2]==0)
  106. returncp-str+2;
  107. if(cp[3]==0)
  108. returncp-str+3;
  109. if(sizeof(longword)>4)
  110. {
  111. if(cp[4]==0)
  112. returncp-str+4;
  113. if(cp[5]==0)
  114. returncp-str+5;
  115. if(cp[6]==0)
  116. returncp-str+6;
  117. if(cp[7]==0)
  118. returncp-str+7;
  119. }
  120. }
  121. }
  122. }
  123. libc_hidden_builtin_def(strlen)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值