我对C中的结构有疑问。所以当你创建一个结构时,你实际上是在定义一块内存的框架。 因此,当您创建结构的实例时,您正在创建一个内存块,以便它能够容纳一定数量的元素。
但是,我对点运算符正在做什么感到有些困惑。 如果我有一个struct Car
并且有一个名为GasMileage
的成员(这是一个int
成员),我可以通过做类似的事情获得GasMileage
的值,
int x = CarInstance.GasMileage;
但是,我对这个点运算符实际发生的事情感到困惑。 点运算符是否只是作为基址的偏移量? 它究竟是如何推断它是一个int?
我想我对幕后发生的事情很好奇。 通过做其他事情可以引用GasMileage
吗? 如
int *GasMileagePointer = (&carInstance + offsetInBytes(GasMileage)); int x = *GasMileage
这只是我快速弥补的事情。 我一直在努力寻找一个好的解释,但似乎没有什么能比将点运算符视为魔术更能解释它。
当你使用.
运算符,编译器根据其前面的字段(和填充)的大小将其转换为struct
内部的偏移量。
例如:
struct Car { char model[52]; int doors; int GasMilage; };
假设int
是4个字节且没有填充,则model
的偏移量为0
, doors
的偏移量为52
, GasMilage
的偏移量为56。
因此,如果您知道成员的偏移量,您可以像这样获得指向它的指针:
int *GasMileagePointer = (int*)((char *)&carInstance + offsetInBytes(GasMile));
转换为char *
是必要的,因此指针算法一次sizeof(carInstance)
1个字节而不是1个sizeof(carInstance)
。 然后需要将结果转换为正确的指针类型,在本例中为int *
是的,点运算符只是从结构的基数应用偏移量,然后访问该地址的值。
int x = CarInstance.GasMileage;
相当于:
int x = *(int *)((char*)&CarInstance + offsetof(Car, GasMileage));
对于具有其他类型T
的成员,唯一的区别是cast (int *)
变为(T *)
。
点运算符只是选择成员。
由于编译器具有关于成员的类型 (以及因此大小 )的信息(实际上是所有成员),因此它知道成员从结构的开头的偏移量并且可以生成适当的指令。 它可以生成基本+偏移访问,但它也可以直接访问成员(或者甚至将其缓存在寄存器中)。 编译器具有所有这些选项,因为它在编译时具有所有必要的信息。
如果没有,就像不完整类型一样 ,你会得到一个编译时错误。
当它工作时,“。” 行为的“。” 运算符等效于获取结构的地址,通过成员的偏移量对其进行索引,并将其转换为成员类型的指针,并取消引用它。 但是,标准规定,有些情况不能保证有效。 例如,给定:
struct s1 {int x,y; } struct s2 {int x,y; } void test1(struct s1 *p1, struct s2 *p2) { s1->x++; s2->x^=1; s1->x--; s2->x^=1; }
编译器可能会认为没有合法的方式p1-> x和p2-> x可以识别同一个对象,所以它可能会重新排序代码,以便对s1-> x取消的++和 – 操作,以及^ = 1对s2-> x取消的操作,从而留下一个什么都不做的函数。
请注意,使用联合时行为是不同的,因为给定:
union u { struct s1 v1; struct s2 v2; }; void test2(union u *uv) { u->v1.x^=1; u->v2.x++; u->v1.x^=1; u->v2.x--; }
common-initial-subsequence规则表示由于u-> v1和u-> v2以相同类型的字段开头,因此访问u-> v1中的这样一个字段相当于访问u-中的相应字段> V2。 因此,不允许编译器重新排序。 另一方面,给定
void test1(struct s1 *p1, struct s2 *p2); void test3(union u *uv) { test1(&(u.v1), &(u.v2)); }
u.v1和u.v2以匹配字段开头这一事实并不能防止编译器假设指针不会出现别名。
请注意,某些编译器提供强制生成代码的选项,其中成员访问的行为始终与上述指针操作相同。 对于gcc,选项是-fno-strict-alias
。 如果代码需要访问不同结构类型的公共初始成员,则省略该开关可能会导致一个人的代码以奇怪,奇怪和不可预测的方式失败。
以上就是c/c++开发分享C结构点运算符究竟做了什么(低级透视)?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/560807.html