简体   繁体   English

指针访问和数组访问之间的值差异

[英]Difference in values between pointer access and array access

Can someone please clarify an incorrect interpretation on my part? 有人可以澄清我的错误解释吗? I know that my understanding is incorrect due my code's resulting output (see the bottom of the question). 我知道由于代码的输出结果,我的理解是不正确的(请参阅问题的底部)。 Thanks in advance. 提前致谢。

To clarify, what does each segment of the following line mean?: 为了澄清,以下各行的每个段是什么意思?:

*(u8 *)((u32)BufferAddress + (u32)i)

And how does it differ from the following line: 它与以下行有何不同:

*(u32 *)((u32)BufferAddress + (u32)i)

My interpretation of the above is: 我对以上内容的解释是:

  1. segment1 = ((u32)BufferAddress + (u32)i) => determine an address as an integer. segment1 =((u32)BufferAddress +(u32)i)=>将地址确定为整数。
  2. segment2 = (u32 *)(segment1) => cast the address to be treated like a pointer, where the pointer is 32 bits in length. segment2 =(u32 *)(segment1)=>将地址转换为指针,指针的长度为32位。
  3. segment3 = *(segment2) => dereference the pointer in order to obtain the value of residing at the calculated address. segment3 = *(segment2)=>取消引用指针,以获得在计算出的地址处的驻留值。

What is incorrect about my interpretation? 我的解释有什么错误? I think my lack of understanding is in the segment2 area... What is the difference between casting (u32 *) and (u8 *)? 我认为我对segment2领域缺乏了解...转换(u32 *)和(u8 *)有什么区别?

Here is the code that made me realize I have a knowledge-gap: 这是使我意识到自己存在知识空白的代码:

Initialization code: 初始化代码:

main(...) {
     ...
     u8 *Buffer = malloc(256);
     ...
     Buffer[0] = 1;
     Buffer[1] = 0;
     Buffer[2] = 0;
     Buffer[3] = 4;
     Buffer[4] = 0;
     Buffer[5] = 0;
     qFunction(... , Buffer, 6, ...);
     ...
}

qFunction(... , const u8 *BufferPointer, u32 BufferLength, ...) {
     u32 BufferAddress;
     ...
     BufferAddress = (u32) BufferPointer;
     ...

     /* Method 1: */
     for (i=0; i < BufferLength; i++)
          printf("%d, %p\n", BufferPointer[i], &BufferPointer[i]);

     /* Method 2: */
     for (i=0; i < BufferLength; i++)
          printf("%d, 0x%lx\n", *(u8 *)(BufferAddress+i), BufferAddress+i);

     /* Method 3: */
     for (i=0; i < BufferLength; i++)
          printf("%d, 0x%lx\n", *(u32 *)(BufferAddress+i), BufferAddress+i);
     ...
 }

The outputs of Method 1 and Method 2 are as I expect (both are the same): 方法1和方法2的输出符合我的预期(两者相同):

1, 0x1000000
0, 0x1000001
0, 0x1000002
4, 0x1000003
0, 0x1000004
0, 0x1000005

However, the output of Method 3 seems weird to me; 但是,方法3的输出对我来说似乎很奇怪。 only part of the result is the same as Method 1/2: 结果的一部分仅与方法1/2相同:

-1442840511, 0x1000000
11141120, 0x1000001
43520, 0x1000002
4, 0x1000003
0, 0x1000004
0, 0x1000005

I'd appreciate any tips or references to reading material. 对于阅读材料的任何提示或参考,我将不胜感激。 Thanks. 谢谢。

*(u8 *)((u32)BufferAddress + (u32)i)
*(u32 *)((u32)BufferAddress + (u32)i)

The top line casts the pointer to an unsigned 8 bit value before dereferencing, while the seconds casts it to an unsigned 32 bit value before dereferencing. 顶行将指针转换为取消引用前的无符号8位值,而秒数则将指针转换为取消引用前的无符号32位值。 The top line derefences a single byte and the bottom one dereferences an entire 4 bytes. 最上面一行取消引用一个字节,最下面一行取消引用整个4个字节。

To address your other question: 要解决您的其他问题:

What is incorrect about my interpretation? 我的解释有什么错误? I think my lack of understanding is in the segment2 area... What is the difference between casting (u32 *) and (u8 *)? 我认为我对segment2领域缺乏了解...转换(u32 *)和(u8 *)有什么区别?

The interpretation of the address being 32 bits in length is true for both top and bottom lines of code. 对于地址的顶行和底行,地址长度为32位的解释都是正确的。

I could nitpick, and say "You didn't give us enough information". 我可以挑剔,说:“您没有给我们提供足够的信息”。 Technically this is true, but it just requires making some assumptions. 从技术上讲,这是正确的,但只需要作一些假设即可。 u8 and u32 aren't standard C types, and you could have them typedefed to anything, but presumably, they represent an unsigned 8 bit value (eg uchar ) and an unsigned 32 bit value (eg unsigned ). u8u32不是标准C类型,您可以将它们定义为任何类型,但是大概它们代表无符号的8位值(例如uchar )和无符号的32位值(例如unsigned )。 Assuming that, let's look at the ones you understand, and explain where that leaves the third one. 假设是这样,让我们​​看一下您所理解的内容,并说明剩下的内容。

BufferPointer is a const u8*, which means it's a constant pointer of type u8. BufferPointer是一个常量u8 *,这意味着它是u8类型的常量指针。 That means the array it's pointing to is of type 8-bit unsigned. 这意味着它指向的数组是8位无符号类型的。

Now, BufferAddress is a u32 - that's typical for pointers, at least on a 32 bit system. 现在, BufferAddress是一个BufferAddress至少在32位系统上,通常用于指针。 Since they're always the size of the bus, on a 64bit system, pointers are 64 bits. 由于它们始终是总线的大小,因此在64位系统上,指针是64位。

So, Method1 is printing the elements of the array and the address of the array. 因此,Method1正在打印数组的元素和数组的地址。 That's fine and cool. 很好,很酷。

Method2: 方法2:

*(u8 *)(BufferAddress+i), BufferAddress+i *(u8 *)(BufferAddress + i),BufferAddress + i

BufferAddress is an unsigned integer, and you're adding values to it to get the other addresses. BufferAddress是一个无符号整数,您正在向其添加值以获取其他地址。 That's a basic point of arrays - the memory will be contiguous, and you access the next element by advancing the number of bytes of each element. 这是数组的基本要点-内存将是连续的,并且您可以通过提高每个元素的字节数来访问下一个元素。 Since it's a u8 array, you just advance by 1. Here's a catch, though - if it was an array of ints, you'd want BufferAddress+(i*4), not BufferAddress+i, because the size of each int is 4 bytes. 因为它是一个u8数组,所以您只需前进1。但是,这很重要-如果它是一个int数组,则您需要BufferAddress +(i * 4),而不是BufferAddress + i,因为每个int的大小为4字节。 Incidentally, this is how pointer arithmetic works in C. If you did `&(((u32 *)BufferAddress) + 1) you'd get 0x100004 instead of 0x100001, because you casted BufferAddress to a 4byte pointer, and the compiler knows that when you're looking at the next element, it has to be 4 bytes away. 顺便说一下,这就是指针算术在C中的工作方式。如果执行了&&((((u32 *)BufferAddress)+ 1),您将得到0x100004而不是0x100001,因为您将BufferAddress强制转换为4byte指针,并且编译器知道当您查看下一个元素时,它必须相距4个字节。

So (BufferAddress+i) is the address of the ith element of the u8 array. 因此(BufferAddress+i)是u8数组的第i个元素的地址。 The (u8 *) casts BufferAddress from a boring integer to a pointer to memory locations of type u8, so that when you do *(u8 *) , the compiler knows to treat it as a u8. (u8 *)将BufferAddress从无聊的整数强制转换为指向u8类型的内存位置的指针,因此,当您执行*(u8 *) ,编译器知道将其视为u8。 You could do (u64 *) , and the compiler would say "Oh! This area of memory is 64 bit", and attempt to interpret the values in that way. 您可以这样做(u64 *) ,编译器会说“哦!此内存区域为64位”,并尝试以这种方式解释值。

Which might make it clear what's happening in Method 3 now. 这可能使方法3中的情况变得清晰起来。 You're getting the appropriate addresses of each array element, but you're telling the compiler "treat this area of memory as 32 bit data". 您将获得每个数组元素的适当地址,但您要告诉编译器“将该内存区域作为32位数据进行处理”。 So each time you use *(u32 *), you're reading 4 bytes of the array and treating it as an unsigned int. 因此,每次使用*(u32 *)时,您都在读取数组的4个字节并将其视为无符号int。 Incidentally, once i >= 3, you're hitting undefined behavior, because you're reading outside of the array. 顺便说一句,一旦i> = 3,您就会遇到未定义的行为,因为您正在读取数组之外的内容。

Let me try to give a visualization of what your memory in that area looks like: 让我尝试以可视化方式显示您在该区域中的存储情况:

0x1000000 = 1
0x1000001 = 0
0x1000002 = 0
0x1000003 = 4
0x1000004 = 0
0x1000005 = 0

For method2, when i = 2, you're looking at BufferAddress (=0x1000000) + 3, ie 0x1000002, which has the number 0 in it. 对于方法2,当i = 2时,您正在查看BufferAddress(= 0x1000000)+ 3,即0x1000002,其中具有数字0。 The compiler knows it's only one byte, so goes with that. 编译器知道它只有一个字节,因此。

But for method3, when i = 3, you're telling the compiler to treat it as 32 bits. 但是对于method3,当i = 3时,您要告诉编译器将其视为32位。 So it doesn't see '0', it see 0, 4, 0, 0, and uses these numbers to come up with an integer value, which will definitely not be 4. 因此它不会看到“ 0”,而是看到0、4、0、0,并使用这些数字得出一个整数值,该值肯定不是4。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM