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

时间:2013-06-26 22:15:51

标签: c arrays pointers memory

有人可以澄清我的错误解释吗?我知道我的理解是不正确的,因为我的代码产生了输出(参见问题的底部)。 提前谢谢。

澄清一下,下一行的每个部分是什么意思?:

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

它与下一行有什么不同:

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

我对上述内容的解释是:

  1. segment1 =((u32)BufferAddress +(u32)i)=>将地址确定为整数。
  2. segment2 =(u32 *)(segment1)=>将指定的地址转换为指针,指针的长度为32位。
  3. segment3 = *(segment2)=>取消引用指针以获取驻留在计算地址的值。
  4. 我的解释有什么不对?我认为我缺乏理解是在segment2领域...... cast(u32 *)和(u8 *)有什么区别?

    以下代码让我意识到我有一个知识差距:

    初始化代码:

    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);
         ...
     }
    

    方法1和方法2的输出正如我所料(两者都相同):

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

    然而,方法3的输出对我来说似乎很奇怪;只有部分结果与方法1/2相同:

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

    我很感激阅读材料的任何提示或参考。 感谢。

2 个答案:

答案 0 :(得分:3)

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

在解除引用之前,顶行将指针强制转换为无符号的8位值,而在解除引用之前,秒将其转换为无符号的32位值。顶行取消反映一个字节,底部取消引用整个4个字节。

解决您的其他问题:

  

我的解释有什么不对?我觉得我缺乏   理解是在segment2领域......有什么区别   在铸造(u32 *)和(u8 *)之间?

对于顶部和底部代码行,地址长度为32位的解释都是正确的。

答案 1 :(得分:3)

我可以挑剔,然后说“你没有给我们足够的信息”。从技术上讲,这是事实,但它只需要做出一些假设。 u8u32不是标准的C类型,你可以将它们的类型定义为任何东西,但大概是,它们表示无符号的8位值(例如uchar)和无符号的32位价值(例如unsigned)。假设,让我们看看你理解的那些,并解释它离开第三个的位置。

BufferPointer是一个const u8 *,这意味着它是一个类型为u8的常量指针。这意味着它指向的数组是8位无符号类型。

现在,BufferAddress是一个u32 - 这是指针的典型,至少在32位系统上。由于它们总是与总线大小相同,因此在64位系统上,指针是64位。

因此,Method1正在打印数组的元素和数组的地址。那很好很酷。

方法2:

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

BufferAddress是一个无符号整数,您要为其添加值以获取其他地址。这是数组的基本点 - 内存将是连续的,您可以通过提高每个元素的字节数来访问下一个元素。因为它是一个u8数组,所以你只需要前进1.这里有一个问题 - 如果它是一个整数数组,你需要BufferAddress +(i * 4),而不是BufferAddress + i,因为每个int的大小是4字节。顺便说一下,这就是指针运算在C中的工作方式。如果你做了`&amp;(((u32 *)BufferAddress)+ 1)你得到0x100004而不是0x100001,因为你把BufferAddress转换为4byte指针,编译器知道当你看下一个元素时,它必须是4个字节。

所以(BufferAddress+i)是u8数组的第i个元素的地址。 (u8 *)将无效整数中的BufferAddress转换为指向u8类型的内存位置的指针,因此当您执行*(u8 *)时,编译器知道将其视为u8。你可以做(u64 *),编译器会说“哦!这个内存区域是64位”,并尝试以这种方式解释这些值。

现在可以清楚地说明方法3中发生了什么。您正在获取每个数组元素的相应地址,但您告诉编译器“将此内存区域视为32位数据”。因此,每次使用*(u32 *)时,您将读取数组的4个字节并将其视为unsigned int。顺便说一下,一旦i> = 3,你就会遇到未定义的行为,因为你正在数组之外阅读。

让我试着想象一下你在那个区域的记忆是什么样的:

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

对于method2,当i = 2时,你正在查看BufferAddress(= 0x1000000)+ 3,即0x1000002,其中的数字为0。编译器知道它只有一个字节,所以就这样。

但对于method3,当i = 3时,您告诉编译器将其视为32位。因此它看不到'0',它看到0,4,0,0,并使用这些数字得出一个整数值,绝对不会是4。

相关问题