【问题标题】:How to access data of another variable by pointing to a slack-byte in a structure?如何通过指向结构中的松弛字节来访问另一个变量的数据?
【发布时间】:2020-01-28 08:31:12
【问题描述】:
#include <stdio.h>
#include <stdlib.h>

struct someStruct {
    int ivar;
    char cvar;
    float fvar;
};

main(argc,argv)
const char** argv;
{
    struct someStruct someObj;
    someObj.ivar = 1;
    someObj.fvar = 2.3;
    someObj.cvar = 'r';
    printf("%u\n",&someObj.fvar);
    printf("%u\n",(&someObj.cvar + 4));
    printf("%f\n",*((&someObj.cvar) + 4));
    printf("%f\n",someObj.fvar);
}

这是我编写的一个程序,它试图通过在 char 的地址上加 4 来访问fvar 的地址。 我知道松弛字节的概念。我试图访问那段记忆,瞧!它正确打印了地址。

printf("%u\n",&someObj.fvar);
printf("%u\n",(&someObj.cvar + 4));

两者都打印相同的地址。

然后我尝试通过以下方式访问fvar:

printf("%f\n",*((&someObj.cvar) + 4));
printf("%f\n",someObj.fvar);

0.000000
2.300000

是我的结果。

然后我意识到 char* 和 float* 的解释不同。

所以,我尝试了从 char* 到 float* 到 float 以及从 char 到 float* 到 float 的各种类型转换,以及在所有可能的点上,例如 typecasting the returned address to float,使用 4.0 而不是 @ 987654329@(我意识到它不应该工作......但它没有)等等。

不知何故,它只是不打印2.300000,而是继续打印0.000000

我在哪里错过了这个概念?

请注意,我有一个 64-bit MinGW 并添加了 slack-byte(我知道有些没有),我已经验证过:

printf("%u",sizeof(someObj.ivar));
printf("%u",sizeof(someObj.fvar));
printf("%u",sizeof(someObj.cvar));
printf("%u",sizeof(someObj));

分别产生44112 ....(sizeof(char) + 3)

附:我知道这是一个可怕的想法,但这是我通常学习概念的方式 XD

【问题讨论】:

  • printf("%u\n",&amp;someObj.fvar); 已经有未定义的行为。 %u 接受 unsigned int,而不是指针。
  • main(argc,argv) const char** argv; 是过时的标准 C 语法。它于 1999 年正式从语言中删除。您从什么来源学习 C?
  • K&R C(第 1 版)于 1978 年出版,距今已有 41 年。我希望你意识到从那时起语言已经发生了很大的变化。
  • 很高兴看到此类问题的参考资料 - cpprefernce sizeofsizeof "返回 size_t 类型的值"。
  • sizeof 产生一个size_t,它不一定与unsigned int 相同(在当今的 64 位平台上通常不是)。

标签: c pointers struct padding sizeof


【解决方案1】:

假设以下情况为真:

 &someObj.cvar + 4 == &someObj.fvar

您可以将指针值转换为正确的类型:

printf("%f\n", *(float*)((&someObj.cvar) + 4));

(&amp;someObj.cvar) 是指向char 的指针,所以*(&amp;someObj.cvar)char%f printf 说明符需要 doublefloat,传递 char 无效。注意:float 在可变参数函数中作为省略号参数中的一个参数传递时,会隐式转换为 double,请参见 ex。 cppreference implicit conversions。您必须将doublefloat 传递给%f,而不是char

注意事项:

main(argc,argv)
const char** argv;
{

不要使用隐式 int 声明和旧的、不推荐使用的、过时的函数声明样式。使用普通样式:

int main(int argc, char **argv) {
  • printf("%u\n",&amp;someObj.fvar); 是未定义的行为。 %u 需要 unsigned char,而不是 float *。您可以使用%p 说明符打印void* 指针:printf("%p\n", (void*)&amp;someObj.fvar); 或将其转换为unsinged intprintf("%u\n", (unsigned int)(uintptr_t)(void*)&amp;someObj.fvar);

  • C 在stddef.h 中声明了一个宏offsetof 来访问“松弛字节”的数量(我更喜欢“填充字节”这个名称)。您可以:printf("%f", *(float*)((char*)&amp;someObj + offsetof(struct someStruct, fvar)));

【讨论】:

  • 那么,你确定&amp;someObj.cvar + 4 == &amp;someObj.fvar 吗?注意:用%u 打印它没有任何意义。
  • 技术上printf %f 期望double。您不能通过 varargs 函数传递 float
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-14
  • 2021-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-29
  • 2018-04-04
相关资源
最近更新 更多