什么是 std::__lg?

tua*_*tit 5 c++ std

作为标题,我不知道std::__lg在谷歌之后是什么意思?这行到底是做什么的:int n = std::__lg(block_sz - pos_l + 1);

Zby*_*000 7

它是计算整数的基于 2 的对数的助手,即它返回数字中最高设置位的索引(或 -1 表示 0)。

即对于 1 它将返回 0,对于 16 它将返回 4,对于 1024 它将返回 10,等等。

这可以用来有效地预测数组的预分配大小,四舍五入到最接近的 2 的幂等等。

请注意,与以 开头的任何其他函数一样__,它是编译器或库的内部函数,因此您不应依赖它的存在,此类代码不可移植。std 库的其他实现可以带有完整的解决方案和类似帮助程序的不同名称(如果它们完全使用类似的东西)。

POSIX 提供了类似的功能 - ffs(),还有ffsl和 ffsll(见同一页面),它是 GNU 扩展,分别使用 long 和 long long。

对于评论中的问题 - 如何从 Java 中使用它。由于上述原因,首先这不是一个好主意,其次它需要为此使用 JNI 包装器。第三也是最重要的 - 实际上没有任何理由。Java 已经提供了类似的方法Integer.heghestOneBit(),但请注意,与描述的 std::__lg 相比,它返回​​ +1,即 0 代表 0,1 代表 1,11 代表 1024,等等。


Chr*_*ckl 5

它是编译器(很可能是 GCC)内部使用的标识符,因为所有带双下划线的标识符都属于编译器实现。

\n\n

在您自己的代码中,任何地方都不应该__lg看到或使用类似的东西。使用标准库的接口,而不是其实现。如果您自己的代码直接使用__lg,那么您无法保证该代码能够通过任何其他编译器甚至同一编译器的任何其他版本进行编译或执行正确的操作。

\n\n

正如 C++ 标准在 \xc2\xa72.10 中所述[lex.name]

\n\n
\n

每个包含双下划线__ 或以下划线开头且后跟大写字母的标识符都保留给实现以供任何使用。

\n
\n\n

至于 GCC 到底是什么,只要看看Google 搜索“std::__lg”就会出现的源代码。

\n\n

根据block_sz和的实际类型pos_l,它应该是这样的:

\n\n
\n
/// This is a helper function for the sort routines and for random.tcc.\n//  Precondition: __n > 0.\ntemplate<typename _Size>\n  inline _Size\n  __lg(_Size __n)\n  {\n    _Size __k;\n    for (__k = 0; __n != 0; __n >>= 1)\n  ++__k;\n    return __k - 1;\n  }\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

或这个:

\n\n
\n
inline int\n__lg(int __n)\n{ return sizeof(int) * __CHAR_BIT__  - 1 - __builtin_clz(__n); }\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

现在,__CHAR_BIT__就像标准CHAR_BIT宏一样。正如GCC 文档所述:

\n\n
\n

定义为 char\n 数据类型表示中使用的位数。它的存在是为了使给定数字限制的标准标头正常工作。您不应直接使用此宏;\n 相反,请包含适当的标头。

\n
\n\n

__builtin_clz是另一个 GCC 特定的函数。GCC 文档再次解释了其目的:

\n\n
\n

返回 x 中前导 0 位的数量,从最高\n 有效位位置开始。如果 x 为 0,则结​​果未定义。

\n
\n\n

我认为如果您需要这样的功能,那么自己编写它就很简单了。事实上,问题是你为什么需要它。您实际问题的真正答案可能在于该行的代码中int n = std::__lg(block_sz - pos_l + 1);

\n\n
\n\n

要记住的事情:

\n\n
    \n
  • 不要在您自己的代码中使用带有两个连续下划线的任何内容。
  • \n
  • GCC是开源的,因此特殊函数或宏的内部实现并不秘密,而且可以很容易地在线浏览。
  • \n
\n