簡體   English   中英

有沒有辦法在 constexpr/consteval 上下文中訪問已知大小的任意數據作為 char 數組?

[英]Is there any way of accessing arbitrary data of known size as a char array in a constexpr/consteval context?

我正在嘗試實現一些可以接收任意數據位(在編譯時已知)並將它們的 CRC 計算為consteval的東西,因此我可以使用它來例如使用 integer 鍵索引此類數據,而無需任何運行時開銷。 當輸入是 char 字符串文字時,我讓它工作,但是當輸入是wchar_t字符串文字時,我正在努力讓它工作。

我收到一個相當神秘的錯誤......

error: accessing value of '"T\000e\000s\000t\000\000"' through a 'const char' glvalue in a constant expression

...這似乎是由在 constexpr 上下文中使用 reinterpret_cast 引起的(這顯然是不允許的)

我的問題是,有沒有辦法將任意數據解釋為普通的舊字節數組? 我不在乎它有多丑陋或缺乏可移植性(只要這一切都發生在編譯時)。 現在,只需使用wchar_t數組作為輸入來解決這個問題就足夠了。 顯然,我可以“只是”為我想單獨處理的每種類型重新實現 CRC 計算,但如果可能的話,我寧願不這樣做(事實上,對於比 POD 數組更復雜的任何事情,這將非常棘手)

作為參考,失敗的代碼如下:

// Details of CRCInternal omitted for brevity
template <size_t len> consteval uint32_t CRC32(const char (&str)[len])
{
    return CRCInternal::crc32<len - 1>(str) ^ 0xFFFFFFFFu;
}

template <size_t len> consteval uint32_t CRC32FromWide(const wchar_t (&filename)[len])
{
    return CRC32(reinterpret_cast<const char(&)[len * sizeof(wchar_t)]>(filename));
}

void main()
{
    CRC32FromWide(L"Test"); // <==== Error
}

C++ object model 通常是虛構的,是編寫代碼的程序員和生成二進制可執行文件的編譯器之間的協議。 對於可執行文件,對象不存在; 它只是存儲在 memory 中的位。 因此,您可以利用 C++ 有數十個后門這一事實,這些后門可用於有效地假裝 object model 不是真實的。 其中許多被聲明為表現出未定義的行為,但沒有編譯器會檢查這些違反 object model 的行為並阻止您。 你違反了合同,但編譯器沒有注意,所以你僥幸逃脫。

這不是常量表達式求值的情況。 編譯后的可執行文件在 CPU 上運行; 常量表達式求值編譯器中運行。 object model 不需要 map 到“位”或“內存”或類似的東西; 它可以是真正的 object model,具有全生命周期跟蹤和分析功能。

因此,C++ 標准要求,在持續評估期間,如果您執行任何顯示 UB 的操作,編譯器必須檢測到這一點並聲明您的程序格式錯誤。 此外, constexpr 代碼完全禁止使用最大的后門: reinterpret_cast

在編譯時,對象不是存儲中的字節。 所以你不能像對待他們一樣對待他們。

這一點尤其重要,因為編譯器的執行環境和最終二進制文件的執行環境不必相同 如果您正在為某些嵌入式系統進行開發,那么您所針對的 CPU 的字節序可能與編譯器在其上執行的 CPU 的字節序不匹配。 因此,如果您能夠以字節的形式訪問任何編譯時數據,那么您在編譯時會得到與運行時不同的答案。

那很糟。

C++20 的std::bit_cast存在並且可以提供幫助,但即使這樣也不能做任何事情。 如果類型是 TriviallyCopyable並且不存儲指針(除其他外),則該類型僅適用於constexpr bit_cast -ing。 這是因為編譯時指針不僅僅是地址; 它們是一些復雜的數據類型,必須記住它指向的static_cast (否則,當您將它們靜態轉換為一些不相關的類型並嘗試通過錯誤的類型訪問 object 時,將無法檢測到)。

但是,如果您將類型限制為可以使用constexpr bit_cast的類型,則可以將它們bit_cast為與其大小相同的數組。

請注意, constexpr bit_cast並不是最容易實現的東西,因為它必須使源 object 數據像在目標 CPU 和環境上執行一樣工作,而不是編譯器正在其中執行的環境。 所以如果目標是big-endian機器而源是little-endian, constexpr bit_cast必須做endian轉換,而且必須在知道source和destination對象的每個組件類型是什么的情況下做這種轉換。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM