我有一个赋值,要求一个人为任何数据类型编写函数。该函数应该打印结构的字节并识别数据结构使用的总字节数,以及区分用于成员和字节的字节用于填充。
我的立即反应,以及大多数类反应都是使用模板。这允许您编写一次函数并收集传递给函数的对象的运行时类型。使用memset和typeid可以轻松完成所要求的内容。但是,我们的教授。刚刚看到我们关于模板和该死的模板的讨论到了地狱。
看到这个之后,我被抛出了一个循环,我正在寻找一点指导作为解决这个问题的最佳方法。我已经研究过的一些事情:
希望我忽略了一个常见的c ++工具,有没有人有任何想法?
答案 0 :(得分:1)
尽可能将函数视为愚蠢,事实上,将其视为不知道任何内容,并且必须将所有信息传递给它。
函数的参数:
uint8_t *
。 (需要打印字节)需要向量来满足打印成员使用的字节和填充使用的字节的要求。您可以选择传递成员的总和。
示例:
void Analyze_Structure(uint8_t const * p_structure,
size_t size_of_structure,
size_t size_occupied_by_members);
此分配的技巧是要弄清楚如何让调用函数确定这些项目。
希望这有帮助。
修改1:
struct Apple
{
char a;
int weight;
double protein_per_gram;
};
int main(void)
{
Apple granny_smith;
Analyze_Structure((uint8_t *) &granny_smith,
sizeof(Apple),
sizeof(granny_smith.a)
+ sizeof(granny_smith.weight)
+ sizeof(granny_smith.protein_per_gram);
return 0;
}
答案 1 :(得分:1)
我有一个赋值,要求一个人为任何数据类型编写一个函数。
这意味着模板(你的教授解雇),void *或可变数量的参数(simiar to printf)。
该函数应该打印结构的字节
void your_function(void* data, std::size_t size)
{
std::uint8_t* bytes = reinterpret_cast<std::uint8_t*>(data);
for(auto x = bytes; x != bytes + size; ++x)
std::clog << "0x" << std::hex << static_cast<std::uint32_t>(*x) << " ";
}
[...]并确定数据结构使用的总字节数,以及区分用于成员的字节和用于填充的字节。
在这一点上,我输了:用于填充的字节(根据定义)不是结构的一部分。考虑:
struct x { char c; char d; char e; }; // sizeof(x) == 3;
x instance{ 0, 0, 0 };
your_function(&instance, sizeof(x)); // passes 3, not 4 (4 for 32bits architecture)
理论上,您也可以将alignof(instance)
传递给函数,但是这不会告诉您内存中字段的对齐方式(据我所知,它不是标准化的,但我可能错了)。
这里有一些可能性:
你的教授。学会了&#34; hacky&#34; C ++在10年或20年前被认为是好的代码并且没有更新他的知识(C风格的代码,指针,直接内存访问和&#34;智能黑客&#34;都在这里)。
他不知道如何准确表达他想要的东西或使用的术语(&#34;为任何数据类型编写函数&#34;太模糊:作为开发人员,如果我得到这个任务,首先要做的是询问细节 - 比如&#34;它将如何使用?&#34;和#34;预期的功能签名是什么&#34;)。
例如,这可以在某种程度上实现 - 使用宏,但如果他希望您使用宏代替函数和模板,那么您应该考虑更换教授。
他的意思是你应该写一些任意数据类型(比如我上面的struct x
)并围绕它定义你的API(不太可能)。
答案 2 :(得分:0)
我不确定这样的函数是否可以在没有最少内省的情况下构建:你需要知道struct成员是什么,否则你只能访问struct的大小。
无论如何,如果代码的用户&#34;合作&#34;
,我的建议是一个无需内省的解决方案。您的函数将作为参数void *和size_t作为struct的地址和sizeof。
0)让用户创建所需类型的结构。
1)让用户调用你的函数,将所有字节设置为0。
2)让用户为结构的每个字段赋值。
3)让用户调用你的函数,记录每个仍为0的字节。
4)让用户调用你的函数,将所有字节设置为1。
5)让用户再次为结构的每个字段赋值。 (与第一次的值相同!)
6)让用户调用你的函数并计算仍然为1并且之前被标记的字节。这些是填充字节。
尝试使用值0然后是1的原因是用户指定的值可能包括字节0;但它们不能同时是字节0和字节1,因此其中一个测试将排除它们。
struct _S { int I; char C } S;
Fill0(S, sizeof(S));
// User cooperation
S.I= 0;
S.C= '\0';
Mark0(S, sizeof(S)); // Has some form of static storage
Fill1(S, sizeof(S));
// User cooperation
S.I= 0;
S.C= '\0';
DetectPadding(S, sizeof(S));
您可以将所有这些打包在一个函数中,该函数接受执行成员赋值的回调函数参数。
void Assign(void* pS) // User-written callback
{
struct _S& S= *(struct _S)pS;
S.I= 0;
S.C= '\0';
}