我試圖在固定大小的緩衝區中創建一條消息,其中我的庫的用戶提供了其中的一些數據。我曾經這樣做是通過給用戶一個指向緩衝區的指針並讓它們寫入它,並通過引用他們寫入的字節數來設置參數size_t
。我想擺脫這種方式,因爲它允許用戶意外地破壞緩衝區,或者錯誤地報告寫入的字節數。爲了做到這一點,我做了以下內容:這個CRTP用例是否被認爲是未定義的行爲?
定義這個結構:
template <class Derived>
struct MsgBase
{
size_t size() const { return sizeof(Derived); }
const char* data() const {
const Derived* dat = static_cast<const Derived*>(this);
return reinterpret_cast<const char*>(dat);
}
};
,我需要的是,如果用戶想要發送某些數據,即它們確定了結構從這個繼承與數據將被寄出。例如:
struct Example : MsgBase<Example>
{
int a;
double b;
char c[7];
};
我有這個類中定義,以幫助他們將數據傳遞到我的圖書館:
class Loader
{
public:
Loader() : size(0), data(0) {}
size_t size() const { return size; }
const char* data() const { return data; }
template<class T> void loadData(const T& t) {
size = t.size();
data = t.data();
}
private:
size_t size;
const char* data;
};
所以我稱他們是這樣的:
{
//pos is a char* to a point in a buffer of data
Loader loader;
onLibraryCall(&loader);
memcpy(pos, loader.data(), loader.size());
}
而且用戶正在這樣做:
void onLibraryCall(Loader* loader)
{
Example e;
e.a = 3;
e.b = 2.7;
e.c[0] = //bla fill out some stuff here
loader->loadData(e);
}
這已經在我測試過的無數的二進制文件中使用不同版本的gcc進行編譯,但是在一個特定的二進制文件中一致地破壞了上面的消息。 gdb和valgrind根本沒有幫助我,如果我嘗試記錄上述呼叫的情況,問題就會消失。這讓我覺得這裏有未定義的行爲,但我並不完全確定這可能是什麼,或者我可以做些什麼來進一步調試它?
我有一個檢查,以確保任何這樣定義的結構是POD。我也知道所有的結構是什麼,現在它們都只是整體類型和固定大小的小陣列的組合。
這是真的!我將通過給加載器指針pos並試着立即執行memcpy來試試這個! – 2014-09-18 16:10:35
這是它 - 行爲固定 – 2014-09-18 18:36:31