簡體   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