当前位置: 代码迷 >> C语言 >> [原创]用地址替代变量的讨论
  详细解决方案

[原创]用地址替代变量的讨论

热度:285   发布时间:2007-10-24 16:54:32.0
[原创]用地址替代变量的讨论

*/ --------------------------------------------------------------------------------------
*/ 出自: 编程中国 http://www.bc-cn.net
*/ 作者: neverTheSame E-mail:zhaoxufeng9997@126.com QQ:475818502
*/ 时间: 2007-10-24 编程论坛首发
*/ 声明: 尊重作者劳动,转载请保留本段文字
*/ --------------------------------------------------------------------------------------


大家都知道,每一个变量都有自己的存储空间。而地址就是用来唯一地标识存储空间。
这样就很容易让我们联想到:可以直接通过地址来代替变量,来参加程序的运算。
也就是说,我们在程序运算中可以不用变量,而直接对地址进行操作。
说了这么多,大家可能还不明白,我到底是什么意思。下面就举几个例子来说明。
例一:
#include<stdio.h>
int main(void)
{
scanf("%d",(int*)0x0100);
printf("%d",*((int*)0x0100));

}
由上例可知,0x0100一个存储空间地址.我们通过int*强制类型转换,
将0x0100的类型转换成int*型.在scanf()函数执行时,将从标准输入设备中输入的
整型值放在以0x0100为首址的空间中.而在printf()函数执行时,*((int*)0x0100)的作用
就是在0x0100为首址的空间中取出一个整型数,然后打印在标准输出设备上.
以上这个例子模拟有变量例子:
#include<stdio.h>
int main(void)
{
int var;/*假设变量的存储空间的首址为0x0100*/
scanf("%d",&var);/*&var就是取var的首址,相当于scanf("%d",0x0100);*/
printf("%d",var);/* *((int*)0x0100)就是var的值.*/
}

例二:
实现一个动态申请一个三维数组(像array[5][5][5).
#include<stdio.h>
#include<malloc.h>
int main(void)
{
*(int****)0x0120=(int***)malloc(sizeof(int**)*5);
for((*(int*)0x0116)=0;(*(int*)0x0116)<5;(*(int*)0x0116)++)
{
*(*(int****)0x0120+(*(int*)0x116))=(int**)malloc(sizeof(int*)*5);
for((*(int*)0x0112)=0;(*(int*)0x0112)<5;(*(int*)0x0112)++)
{
*(*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112))=(int*)malloc(sizeof(int)*5);
for((*(int*)0x0108)=0;(*(int*)0x0108)<5;(*(int*)0x0108)++)
*(*(*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112))+(*(int*)0x0108))=1;
}
}
for((*(int*)0x0116)=0;(*(int*)0x0116)<5;(*(int*)0x0116)++)
for((*(int*)0x0112)=0;(*(int*)0x0112)<5;(*(int*)0x0112)++)
{
for((*(int*)0x0108)=0;(*(int*)0x0108)<5;(*(int*)0x0108)++)
printf("%d ",*(*(*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112))+(*(int*)0x0108)));
printf("\n");
}

}

相关的解释如下:

#include<stdio.h>
#include<malloc.h>
int main(void)
{
/*申请一个可以存放5个二级指针的空间,
并把申请到的空间的首址的存放到0x0120为首址的空间中。
相当于:char ***array=NULL;
array=(int***)malloc(sizeof(int**)*5);*/
*(int****)0x0120=(int***)malloc(sizeof(int**)*5);

/*用一个循环,循环的次数为5,空间0x0116存储控制循环的次数值。
相当于for(i=0;i<5;i++)*/
for((*(int*)0x0116)=0;(*(int*)0x0116)<5;(*(int*)0x0116)++)
{
/*申请一个可以存放5个一级指针的空间,
并把申请到的空间的首址的存放到*(int****)0x0120+(*(int*)0x116)为首址的空间中。
相当于:array[i]=(int**)malloc(sizeof(int*)*5);*/
*(*(int****)0x0120+(*(int*)0x116))=(int**)malloc(sizeof(int*)*5);

/*用一个循环,循环的次数为5,空间0x0112存储控制循环的次数值。
相当于for(j=0;j<5;j++)*/
for((*(int*)0x0112)=0;(*(int*)0x0112)<5;(*(int*)0x0112)++)
{
/*申请一个可以存放5个整型数据的空间,
并把申请到的空间的首址的存放到*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112)
为首址的空间中。相当于:array[i][j]=(int*)malloc(sizeof(int)*5)*/
*(*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112))=(int*)malloc(sizeof(int)*5);

/*用一个循环,循环的次数为5,空间0x0108存储控制循环的次数值。
相当于for(k=0;k<5;k++)*/
for((*(int*)0x0108)=0;(*(int*)0x0108)<5;(*(int*)0x0108)++)
/*将首址为*(*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112))+(*(int*)0x0108)的
空间赋值为1。相当于array[i][j][k]=1;*/
*(*(*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112))+(*(int*)0x0108))=1;
}
}

/*用一个循环,循环的次数为5,空间0x0116存储控制循环的次数值。
相当于for(i=0;i<5;i++)*/
for((*(int*)0x0116)=0;(*(int*)0x0116)<5;(*(int*)0x0116)++)
/*用一个循环,循环的次数为5,空间0x0112存储控制循环的次数值。
相当于for(j=0;j<5;j++)*/
for((*(int*)0x0112)=0;(*(int*)0x0112)<5;(*(int*)0x0112)++)
{
/*用一个循环,循环的次数为5,空间0x0108存储控制循环的次数值。
相当于for(k=0;k<5;k++)*/
for((*(int*)0x0108)=0;(*(int*)0x0108)<5;(*(int*)0x0108)++)
/*将首址为*(*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112))+(*(int*)0x0108)的
空间的数据打印。相当于printf("%d ",array[i][j][k]);*/
printf("%d ",*(*(*(*(int****)0x0120+(*(int*)0x0116))+(*(int*)0x0112))+(*(int*)0x0108)));
printf("\n");
}

}


优点:
访问速度快。(由于,CPU直接用地址查找数据)
程序的效率高。(由于,减少了其它用于对变量操作的指令,从而对运算操作的指令比例大)
生成的可执行文件小。(由于,变量直接用地址存取,减少了指令数量。)

缺点:
程序可读性差。
直接使用地址很容易混淆。(如,动态申请的空间是否被用作变量空间去使用。)
对程序员要求很高。(如程序员需要知道,每种类型所占用的字节空间大小。)

搜索更多相关的解决方案: 变量  地址  

----------------解决方案--------------------------------------------------------
没优点把........

保护模式下不会允许你这么做的...
实模式和虚拟86模式还能运行.



----------------解决方案--------------------------------------------------------
ls正解

----------------解决方案--------------------------------------------------------
支持二楼
----------------解决方案--------------------------------------------------------
我觉得运行如果这么写程序,如果程序超过100行,如果程序真的能运行,系统崩溃的可能性大于60%,各种软件随机挂掉可能性大于90%
----------------解决方案--------------------------------------------------------
虽然有一些优点,但是相对来说他对程序员的要求高了很多。可读性差而且容易出错,所以这种方法理论可行,但不适用于实践。对于初学者更是不适用了!
----------------解决方案--------------------------------------------------------

二楼有没有在保护模式运行过这样类似的程序呢?

我在网上查了一下保护模式的一些概念.
保护模式就是对程序的运行加以保护,所以说保护模式较实模式的增强的最主要体现还不是寻址能力而是对多任务的支持,所提到的保护就是对不同任务间和同一任务内的程序加以保护,使它们的运行不受对方“有意”或“无意”影响,但同时也要对两个任务都要用到的部分代码实现共享。另外一个重要的增强就是对虚拟存储器的支持,从一定意义上说可以使程序设计人员不必考虑物理内存的大小。


----------------解决方案--------------------------------------------------------
回复:(neverTheSame)[原创]用地址替代变量的讨论

优点:
访问速度快。(由于,CPU直接用地址查找数据)
程序的效率高。(由于,减少了其它用于对变量操作的指令,从而对运算操作的指令比例大)
生成的可执行文件小。(由于,变量直接用地址存取,减少了指令数量。)

缺点:
程序可读性差。
直接使用地址很容易混淆。(如,动态申请的空间是否被用作变量空间去使用。)
对程序员要求很高。(如程序员需要知道,每种类型所占用的字节空间大小。)

你说的这些优点机器语言全有而且更强,为什么要开发出高级语言呢?高级语言的诞生是为了追求效率吗?
我想高级语言的诞生,本来就是为了缩短硬件和程序员之间的鸿沟,为了使程序员从复杂的CODING中解脱出来。


----------------解决方案--------------------------------------------------------
以下是引用neverTheSame在2007-10-24 23:58:24的发言:

二楼有没有在保护模式运行过这样类似的程序呢?

我在网上查了一下保护模式的一些概念.
保护模式就是对程序的运行加以保护,所以说保护模式较实模式的增强的最主要体现还不是寻址能力而是对多任务的支持,所提到的保护就是对不同任务间和同一任务内的程序加以保护,使它们的运行不受对方“有意”或“无意”影响,但同时也要对两个任务都要用到的部分代码实现共享。另外一个重要的增强就是对虚拟存储器的支持,从一定意义上说可以使程序设计人员不必考虑物理内存的大小。

一般我们所说的保护模式所谈的范围就是在IA-32系列cpu 所出现的,区别于实模式和运行在保护模式下的虚拟86模式.


我在windows下运行用vc编译连接的exe文件应该就是 保护模式下运行过这样类似的程序,

保护模式下相对于实模式寻址能力增加,32位指针可以寻找2^32个地址,也就是最多可以到4G,这4G只是程序可以寻找到的地址.

但是在指针中所给出的地址并不就是实际的物理地址,需要经过段存储机制和页存储机制的两级映射才能找到实际的物理地址,

同时还要进行复杂的保护级检查,

保护级分为0,1,2,3 共4级,只有运行在0级的操作系统才有权利访问所有的数据段,应用程序在3级,它的数据段选择子和描述符都是经过操作系统允许并由操作系统建立的.应用程序只能在操作系统允许的地址范围内读写数据,而且每个数据段都有读写属性.不是由你应用程序随便读写的.

另外 c代码经过编译连接后 的机器指令中 并不存在变量名..只存在该变量相对于某一段的基地址的偏移值, 你用立即数100寻址在保护模式下也只能是相对于某段的偏移.

速度不快.效率不高.所节省的几个字节的空间我觉的可以忽略不计把.

我目前只能理解到此,不对请指正


----------------解决方案--------------------------------------------------------

大家好,别了一段时间,今天写点,不对见谅,水平太低
这个问题涉及到windows的保护机制
在windows中使用段页式内存管理,在保护模式下段寄存器内容是选择符selector,在GDT或者LDT中选择段描述符,请求特权级是将要访问段的特权级的;一般操作系统是通过页式来管理内存,这里就有程序不可见寄存器
CPU设了四个特权级0-3,最高为0,windows只使用了0和3
特权级0是操作系统的内核和各种硬件驱动程序80000000-FFFFFFFF,特权级运行各种应用程序00000000-7FFFFFFF,十六进制哦.CS段寄存器的最低两位表示当前运行的特权级,11就是特权级3.特权级0可以读写所有内存空间,而特权级3只能使用用户地址空间,而不能使用系统地址空间,也就是内存化了两个区.在windows98中可以修改IDT,给了CIH一个机会.还有很多个保护,就不多说了,如果不遵循就会发生保护异常.

印象比较深的是当时看的一个例子
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char **argv)
{
unsigned int var=10;
unsigned int* ptr1=&var;
unsigned int* ptr2=(unsigned int*)0xC0000000L;
printf("*(0x%08x)=",ptr1);
printf("0x%08x\n",*ptr1);
printf("*(0x%08x)=",ptr2);
printf("0x%08x",*ptr2);
}

运行后会有警告对话框,意思就是C0000000H指向了系统空间
如果大家学过windows汇编,和我有一样的书的话,可以找到这个例子
现在也许写的有什么地方不符,也没办法


----------------解决方案--------------------------------------------------------
  相关解决方案