【问题标题】:typecast long pointer issue类型转换长指针问题
【发布时间】:2013-03-26 20:10:29
【问题描述】:
  char *sBuffer=new char[20];
    char * sStringStart = sBuffer;

    long * plMsgStart = (long *) sBuffer;// what is this line doing

    long i=500;

    *plMsgStart = i // what is this line doing

最后一行是在 char 数组中分配 500 吗?但是当我打印数组时,我得到了垃圾值

大家好,下面是实际代码,我在将代码从 c++ 转换为 c# 时遇到它,下面的代码是 c++ 函数的一部分,现在为什么下面的函数给出垃圾值?

char *sBuffer=new char[20];
char * sStringStart = sBuffer;
BSTR bsMsgBody= SysAllocString(L"Helo");
sStringStart+=4;
long * plMsgStart = (long *) sBuffer;

long l=50;

*plMsgStart=l;

sprintf(sStringStart, "%S", bsMsgBody);

printf("%S",sBuffer);

【问题讨论】:

  • 假设它不疯狂,第一个 sizeof(long) 字符被视为一个长变量并设置为 500。取决于数据存储方式的字节序。是的,它看起来像垃圾,但是通过它,你可以看到“500”是如何存储的

标签: c++ c


【解决方案1】:

这是一个演员表。它说“我知道我在做什么,我想把这个char* 当作long* 对待”。之后,它将i 分配给第一个元素(相当于plMsgStart[0] = i;

根据long 的大小,您将覆盖char 数组中的前4 个或8 个元素。打印它仍然是未定义的行为,因为 sBuffer 一开始就没有以 null 结尾。

如果你这样做了

 char *sBuffer=new char[20]();

然后尝试打印sBuffer(在long 覆盖之后),您将看到与500 的二进制表示相对应的4(或8)个字符。

视觉

 char *sBuffer=new char[20];

 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | | | | | | | | | | | | | | | | | | | | |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

 long * plMsgStart = (long *) sBuffer;

 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |       |       |       |       |       |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                 ^^^^^
    note this is still the same memory,
   but "seen through the eyes" of a long*


 *plMsgStart = 500;

 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |  500  |       |       |       |       |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

【讨论】:

  • 我认为整个事情都是 UB,因为它违反了类型别名规则。而且可能还有对齐问题...
  • 认为是这样;它通过指向不兼容类型的指针访问对象(我在这里从 C 中的规则略微推断,可能在 C++ 中有所不同)。至于对齐,这肯定是个问题(取决于您的平台允许的情况)。
  • @OliCharlesworth 我认为new 返回一个正确对齐的指向字长的指针。我不确定是不是,但我对此表示怀疑。
  • 是否保证对齐?
  • 但是为什么 printf("%s",sBuffer);给出垃圾值。
【解决方案2】:

此代码创建一个名为 sBuffer 的 20 字节长缓冲区,然后在缓冲区的第一个 n 字节中存储值为 500 的 long,其中 n 是存储 @987654324 所需的字节数@ 在你的系统上。

long * plMsgStart = (long *) sBuffer;// what is this line doing

这一行告诉编译器您希望plMsgStartsBuffer 是同一个内存块,但该块应被视为存储longs。

【讨论】:

  • 但是为什么 printf("%s",sBuffer);给出垃圾值
  • 因为 %s 需要一个包含 ASCII 值的字节数组,后跟一个值为 0 的字节。如果你想打印出500,那么你需要printf("%ld", plMsgStart[0]);
【解决方案3】:

...我不确定如何使它更简单,但我会尝试:

char *sBuffer // sBuffer is a pointer to a character type

long * plMsgStart  // plMsgStart is a pointer to a long type

(long *) sBuffer;// this tells the compiler that I want my char pointer to be treated
                 // as a long pointer during this assignment.

这使得plMsgStart 指向sBuffer

*plMsgStart = i; // this is dereferencing the pointer, it says: 
                 // "at the current memory location" store the value i

所以实际上,sBuffer 指向的内存被设置为500 的值,如果您尝试长时间访问它,您应该看到 500;如果您尝试以 char(或 char 数组)的形式访问 sBuffer,您很可能会得到垃圾。这是typecast 的完美理由,因为编译器不应该抱怨你所做的任何事情,但你只是溢出了字符数组的第一个元素(char 的值最多为 255 )

您将 500 存储到该内存中,即:

0000 0001 1111 01002 如果你以字节的形式看这个:

[00000001] [11110100] ==> [0x1][-0x12](有符号)

[00000001] [11110100] ==> [0x1][0xF4](无符号)

因此,当您尝试打印该“字符串”时,您会看到垃圾(或者如果您的系统上的charunsigned,则最多是一个“O”)。

【讨论】:

  • 因为它是一个数组,并且他将其转换为类型long,第一个sizeof(long) 将容纳500?。 char 应该取 -128 到 127?
  • @Koushik,您对第一部分的看法是正确的(至少在大多数系统上)。关于char,标准没有定义普通char 是有符号还是无符号。所以,“正确”的范围是 CHAR_MINCHAR_MAX
  • @Alok 感谢您的更正。所以'char'的符号是实现定义的?
  • @Koushik - 数组只是一堆连续的字节。 char 的大小为 1 字节,long 的大小取决于您的系统,但 8 字节是安全的选择。所以从技术上讲,是的,您可以将long 存储到大小为 20 的字符数组中,并以 long 形式访问它。但这没有任何意义...... 20 个字节只能存储 2 个完整的 longs .. WRT 一个 char 保存的值,一个 char 可以保存的 MAX(无论符号)是 255,所以我提到了这个数字跨度>
  • @Mike 我同意这一点,但是您的 sBuffer 的第一个元素设置为 500 是我在评论时想到的。
猜你喜欢
  • 2021-09-20
  • 2020-06-15
  • 1970-01-01
  • 2015-02-14
  • 2012-06-18
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多