繁体   English   中英

在编译时初始化非常大的 C++ std::bitset

[英]Initializing very large C++ std::bitset at compile time

我想存储 2个 16位的 static 常量位集,其中 1 和 0 的特定序列永远不会改变。

我想过使用这篇文章提出的初始化字符串:

std::bitset<1<<16> myBitset("101100101000110 ... "); // the ellipsis are replaced by the actual 65536-character sequence

但是编译器(VS2013)给了我“字符串太长”的错误。

更新

我尝试按照上面链接的帖子中的建议将字符串拆分成更小的块,如下所示:

std::bitset<1<<16> myBitset("100101 ..."
                            "011001 ..."
                            ...
                            );

但我收到错误C1091: compiler limit: string exceeded 65535 bytes in length 我的字符串是 65536 字节(技术上是 65537,带有 EOS 字符)。

我还有哪些其他选择?

更新

感谢luk32 ,这是我最终得到的漂亮代码:

const std::bitset<1<<16> bs = (std::bitset<1<<16>("101011...")
    << 7* (1<<13)) | (std::bitset<1<<16>("110011...")
    << 6* (1<<13)) | (std::bitset<1<<16>("101111...")
    << 5* (1<<13)) | (std::bitset<1<<16>("110110...")
    << 4* (1<<13)) | (std::bitset<1<<16>("011011...")
    << 3* (1<<13)) | (std::bitset<1<<16>("111011...")
    << 2* (1<<13)) | (std::bitset<1<<16>("111001...")
    << 1* (1<<13)) | std::bitset<1<<16>("1100111...");

您并没有真正拆分文字。 无论如何,它都会被连接起来进行编译。 您受到编译器的限制。 我认为没有办法在 MSVC 中增加这个限制。

您可以将其拆分为两个文字,初始化两个位集,移动第一部分并与另一部分进行OR

就像是:

#include <iostream>
#include <string>
#include <bitset>

 
using namespace std;
int main()
{
    std::bitset<8> dest("0110");
    std::bitset<8> lowBits("1001");

    dest <<= dest.size()/2;
    dest |= lowBits;
    std::cout << dest << '\n';
}

如果您查看-02处的 clang 编译器 output ,它会优化为加载105 ,即01101001

我的测试表明,如果你将8换成1<<16 ,它使用 SSE,所以它应该是相当安全的赌注。 它没有像816那样丢弃文字,因此可能会有一些运行时开销,但我不确定您是否可以做得更好。

编辑:

我做了更多测试,这是我的游乐场

#include <iostream>
#include <string>
#include <bitset>
 

using namespace std;
int main()
{
    //static const std::bitset<16> set1( "01100110011001100110011001100110");
    static const std::bitset<16> set2(0b01100110011001100110011001100110);

    static const std::bitset<16> high(0b01100110);
    static const std::bitset<16> low (0b01100110);
    static const std::bitset<16> set3 = (high << 8) | low;
    std::cout << (set3 == set2) << '\n';
}

除了 clang 之外,我无法在任何编译器上对const char*构造函数进行编译时优化,并且最多可以使用 14 个字符。 如果您从unsigned long long初始化一堆bitset并移位并将它们组合在一起,则似乎有一些 promise :

static const std::bitset<128> high(0b0110011001100110011001100110011001100110011001100110011001100110);
static const std::bitset<128> low (0b1001100110011001100110011001100110011001100110011001100110011001);
static const std::bitset<128> set3 = (high << high.size()/2) | low;
std::cout << set3 << '\n';

这使得编译器坚持二进制数据存储。 如果可以使用带有constexpr的较新编译器,我认为可以将其声明为从ull构造的bitset数组,并通过constexpr function 将它们连接起来并绑定到constexpr const变量,这应该可以确保最佳优化. 编译器仍然可以 go 对你不利,但没有理由。 也许即使没有constexpr它也会生成非常优化的代码。

您可以考虑完全跳过编译,并且简单地:

  • 将数据组装成 object 文件(段.rodata ),为其导出符号及其大小。
  • .h文件中将这些符号声明为extern const
  • 使用这些符号并将您的程序链接到此 object 文件。

我没有方便的 MASM32 来编写一个实际有效的完整答案,但我经常将这种技术与 GAS 和 LD 一起使用,它可以解决很多问题。 (按需加载,其他单独数据文件的安全描述符,极快的编译时间......)

请注意,这就是 VS 资源编译器所做的,简而言之......所以您可以将数据作为资源包含并获取指向它的指针。

不可能有这样的static std::bitset因为:


如果允许在运行时构造,则只需将字符串文字拆分为多个小于 2048 个字符的较小字符,以防总长度小于 65536:

ANSI 兼容性要求编译器在连接后接受最多 509 个字符串文字。 Microsoft C 中允许的字符串文字的最大长度约为 2,048 字节。 但是,如果字符串文字由用双引号括起来的部分组成,则预处理器会将这些部分连接成一个字符串,并且对于连接的每一行,它会在总字节数中添加一个额外的字节。

[...]

虽然单个带引号的字符串不能超过 2048 字节,但可以通过连接字符串来构造大约 65535 字节的字符串文字。

https://docs.microsoft.com/en-us/cpp/c-language/maximum-string-length?view=msvc-160

如前所述,较长的字符串必须手动连接。 这里

const int LENGTH = 1 << 16;
std::bitset<LENGTH> myBitset(
    "100101 ..."  // 2ᴺ bits
    "011001 ..."  // 2ᴺ bits
    ...
    "001011 ...", // must be one shorter than the previous lines: 2ᴺ⁻¹ bits
    LENGTH - 1    // size
);
myBitset[LENGTH - 1] = 1; // set the final bit

或者,只需使用数组而不是字符串文字:

static const char BITSET[LENGTH] = {
    '1', '0', '0', '1',...
    ...
    '0', '1', '0', '0'
};
std::bitset<LENGTH> myBitset(BITSET, sizeof(BITSET));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM