在以下code -
中#include <iostream>
using namespace std;
struct S1{
int a; int b; int c; int d;
};
struct S{
int a; int b;
};
int main() {
S1 obj1;
obj1.a = 1;
obj1.b = 2;
obj1.c = 3;
obj1.d = 4;
cout << obj1.a << " "
<< obj1.b << " "
<< obj1.c << " "
<< obj1.d << "\n";
// more code
auto ptr = reinterpret_cast<S *>(&obj1);
cout << ptr->a << " " << ptr->b << "\n";
// more code
// someFunc(ptr, sizeof(obj1));
}
我将值分配给结构S1的成员,然后通过S
原始reinterpret_cast
到S1
将其作为结构S
指针用于其他地方。这很好。
现在提前一点,我有一个函数someFunc(const void *ptr, int len)
,它将const void *
指针和长度传递给正在传递的结构。在这种情况下,它应该将S1
结构传递给它,并且在其中有一些memcpy
调用来复制结构并处理该副本。 我可以这样做吗? -
// more code
someFunc(ptr, sizeof(obj1));
}
意味着将reinterpret_cast
指针传递给此函数和原始S1
结构的大小,或者我是否必须再次reinterpret_cast
将其返回S1
然后再次传递指针
不必reinterpret_cast
再次使用原始类型可以为类似类型S1
保存一些切换案例。请注意,someFunc
可以根据传入的size
轻松找到类型,因为这些相似类型的大小差异很大。
答案 0 :(得分:2)
struct的地址是struct的第一个字节的地址。即使我在标准中找不到任何引用,它也是C ++中常见的习惯用法(就像在C中一样)将指向POD结构(或多或少是C结构)的指针转换为指向初始子序列的指针那个班。转换为void *
时,两者都会给出相同的值。
所以用你的记号:
someFunc(ptr, sizeof(obj1));
和
someFunc(obj1, sizeof(obj1));
是完全相同的电话。
答案 1 :(得分:1)
是的,
someFunc(ptr, sizeof(obj1));
很好......但仅仅因为obj1 实际类型为S1
。我对你的评论有点怀疑&#34;保存一些像S1和#34;类似类型的开关案例。
答案 2 :(得分:1)
我正在为结构S1的成员分配值,然后通过将原始S1重新解释为将其作为结构S指针在其他地方使用它们。这样可以正常工作。
现在有点提前,我有一个函数someFunc(const void * ptr,int len),它将const void *指针和长度传递给正在传递的结构。
我可以这样做吗?
你可以。你永远不应该。
你的代码中应该有这样一个API的唯一原因是,如果你没有写它但必须使用它,没有权利触摸它所在的代码,和/或没有时间预算来包装或重写它(这应该需要一个小时左右)。
替代代码,使用继承(避免reinterpret_cast和整个问题):
struct S { int a, b; }; // defines common behavior between structures
// this is what base classes are for
struct S1: S { int c, d; }; // inherit S
someFunc:
auto someFunc(S& sref);
S s{1, 2};
S1 s1{1, 2, 3, 4};
someFunc(s); // works
someFuncf(s1); // also works
不必将reprepret_cast再次重新设置为原始类型将为我节省一些类似类型的开关案例。
必须在用户类型(您的S结构)上键入reinterpret_cast表示您没有将常见行为提取到公共基类/结构中。
答案 3 :(得分:1)
我正在为结构S1的成员分配值,然后通过将原始S1重新解释为将其作为结构S指针在其他地方使用它们。这样可以正常工作。
这是未定义的行为。一个可能的症状是它“工作正常”。
S1
和S
是布局兼容的,但它们不是同一个对象。 S1
或S
住在该位置,而不是两者。
访问实际上并不存在未定义行为的对象。
你想要的是指针 - 不可转换。
这是合法的C和C ++:
struct S{
int a; int b;
};
struct S1{
S s;
int c; int d;
};
现在,可以将指向S1
的指针重新解释为指向S
的指针,a
和b
与s.a
相同原始s.b
中的S1
。
在C ++中,这也可以通过继承来完成:
struct S1:S {
int c; int d;
};
在这两种情况下,都存在S1
和S
对象,因此您永远不会访问不存在的对象。
你所做的事通常会奏效;但在C ++标准下,它是未定义的行为。
作为一个实际问题,优化器可以假设它永远不会发生,不能访问S
可以修改S1
的状态,反之亦然,这可能会导致程序中出现意外行为。当您将程序升级到链接时间优化时,可能会自发地出现新的和极其危险的行为。
S1 obj1 { 1,2,3,4 };
static_cast<S*>(&obj1).a=99;
std::cout << obj1.a; // can legally print out 1, or anything else really
std::cout << obj1.a; // it could now print out 99. Why? Undefined behavior
一旦你有实际的指针可互换性,C ++标准确保:
S1 obj1 { 1,2,3,4 };
auto* s = reinterpret_cast<S*>(&obj1);
void* ptr = s;
Assert( static_cast<S1*>(ptr) == &obj1 );
Assert
通过。