正文

内存和地址2009-02-26 10:26:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/xman/41056.html

分享到:

计算机的内存由数以亿万计的位(bit)组成,每个位可以容纳值01。由于一个位所能表示的值得范围太有限,所以单独的位的用处不大,通常许多位组成一组作为一个存储单位,这样就可以存储范围较大的值。以下展示了现实机器中的一些内存位置:

100

101

102

103

104

105

106

107

 

 

 

 

 

 

 

 

这些位置的每一个都被称为字节(byte),每个字节都包含了存储一个字符所需要的位数。在很多现代的机器上,每个字节包含8个位,可以存储无符号值0255,或者有符号值-128127。实际内存中每个位置总是包含一些值。每个字节通过地址来标识,如上图中的数字所示。

为了存储更大的值,我们把两个或更多个字节合在一起作为一个更大的内存单位。例如,很多机器以字为单位存储整数,每个字一般由24个字节组成。下图所示内存位置与上图相同,但这次它以4个字节的字来表示。

100

 

 

 

104

 

 

 

 

 

尽管一个字(INT32)包含了4个字节,它仍然只有一个地址。至于它的地址是它最左边那个字节的位置还是最右边那个字节的位置,不同的机器有不同的规定。另一个需要注意的硬件事项是边界对齐(boundary alignment)。在要求边界对齐的机器上,整型值存储的起始位置只能是某些特定的字节,通常是24的倍数。但这些问题是硬件设计者的事情,它们很少影响C程序员。我们只对两件事情感兴趣:

1.内存中的每个位置由一个独一无二的地址标识。

2.内存中的每个位置都包含一个值。

在实际程序中我们经常根据需要借助强大的指针对一块内存进行操作,再按字节组合析取出所需数据,平时的程序中经常用到通用指针void*(LPVOID)的妙处就在于可以按照需要操作一块内存,以取所需值类型。

以下测试小程序向我们清晰的展示了三种字节析取情况:

#include <stdio.h>

#include <windows.h>

void main(void)

{

         int i;

         BYTE byte[9] = {48, 49, 50, 51, 52, 53, 54, 55,0};

 

         printf("1byte16进制BYTE:\n");

         for(i = 0; i < 9; i++)

         {

                   printf("byte[%d] = %x \n", i, byte[i]);

         }

         printf("----------------------------------\n");

         printf("字符串byte[9]:\n");

         BYTE *pBYTE = byte;

         printf("*pBYTE = %s \n", pBYTE);

         printf("----------------------------------\n");

         printf("2byte组合而成的16进制INT16:\n");

         INT16 *pINT16 = (INT16*)pBYTE;

         for (i = 0; i < 4; i++)

         {

                   INT16 i16 =  *(pINT16 + i); // Debug

                   printf("*(pINT16 + %d) = %x \n", i, *(pINT16 + i));

         }

         printf("----------------------------------\n");

         printf("4byte组合而成的16进制INT32:\n");

         INT32 *pINT32 = (INT32*)pBYTE;

         for (i = 0; i < 2; i++)

         {

                   INT32 i32 = *(pINT32 + i); // Debug

                   printf("*(pINT32 + %d) = %x \n", i, *(pINT32 + i));

         }

         printf("----------------------------------\n");

         return;

}

         说明*(pINT16 + 0) = 3130而不是3031,这是因为Windows操作系统使用的是小序在前的存储方式,也即在起始地址处存放整数的低序号字节(低地址低字节)。

    以下展示了两种强制类型转换:

    // 多字节的截取(容易造成数据的丢失!)

         int i1 = 0x12345678; // 小序存放顺序4byte0x78,0x56,0x34,0x12

         short s1 = (short)i1; // 析取2byte0x5678

         char c1 = (char)i1; // 析取1byte0x78

    // 短字节的扩展        

         short s2 = 0x5678; // 小序存放顺序2byte0x78,0x56

         int i2 = (int)s2; // 扩展2byte,高位补00x00005678

 

#define uchar unsigned char

 

// 打印1个字节数的二进制位串

void binary_print_byte(uchar c)

{

    for(int i = 0; i < 8; ++i)

    {

        if((c << i) & 0x80) // 左移

            cout << '1';

        else

            cout << '0';

    }

 

    cout << ' ';

}

 

// 打印4字节数的二进制位串

template <class T>

void binary_print_4byte(T val)

{   

    void *f = &val; // 取地址

    uchar c_save[4] = {0};

    int i;

 

    for(i = 0; i < 4; i++)

        c_save[i] =  *((uchar*)f + i);

 

    // Windows采用小序存储!

    for(i = 4; i != 0; i--)

        binary_print_byte(c_save[i-1]);

   

    cout << endl;

}

 

参考:

C/C++基本数据类型

Pointers in C   

Pointers   

http://www.augustcouncil.com/~tgibson/tutorial/ptr.html

Pointers and Memory

http://cslibrary.stanford.edu/102/PointersAndMemory.pdf

阅读(3539) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册