我试图在固定大小的缓冲区中创建一条消息,其中我的库的用户提供了其中的一些数据。我曾经这样做是通过给用户一个指向缓冲区的指针并让它们写入它,并通过引用他们写入的字节数来设置参数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