zoukankan      html  css  js  c++  java
  • 面试经典大端小端实践应用1

    我在前面总结过大端小端的基本概念,一句话说就是对于变量的二进制表示,如果低地址存放的是二进制位的高位,那么说明CPU是大端模式,反之则为小端模式。的确有了这句话的总结之后很容易记忆,我也自以为得其真谛,但是在接下来看题目,做笔试题的过程中发现对于大端小端的理解,还得结合其它的知识点来看。


    首先就是栈生长的方向问题,栈生长的方向是由高地址向低地址生长,也就是说栈底的地址高一些,而堆则相反,下面结合一个具体的例子来说明,请看如下代码:

    #include <stdio.h>
    
    #include <stdlib.h>
    
    
    
    int main(int argc, char const *argv[])
    
    {
    
    	int a=0x9abc0e0d;
    
    	int b=0x12345678;
    
    	
    
    	char *p=(char*)&b;
    
    	char *q=p+2;
    
    
    
    	int x=*q;
    
    	int y=*(int *)q;
    
    	printf("&a=%x,&b=%x\n",&a,&b );
    
    	printf("x=%x,y=%x\n",x,y );
    
    
    
    	int *pc=(int*)malloc(sizeof(int));
    
    	int *pd=(int*)malloc(sizeof(int));
    
    
    
    	*pc=0x12345678;
    
    	*pd=0x9abc0e0d;
    
    
    
    	char *c=(char*)pc;
    
    	char *d=c+2;
    
    	int m=*d;
    
    	int n=*(int*)d;
    
    
    
     	printf("pc=%x,pd=%x\n",pc,pd );
    
     	printf("m=%x,n=%x\n",m,n );
    
    
    
    	return 0;
    
    }
    输出如下:
    image


    现在对结果进行分析,首先,很清楚地可以看到栈地址是从高往低生长的,一般而言,在debug模式下面,生长不一定连续,会有一些无用字符填充,但在release模式下一般是连续的。

    而在我用gcc编译运行得出的结果中我们可以看到貌似是连续的。而堆的结果说明堆是由低到高生长的,而且是不连续的。
    现在分析大端小端问题。对于a,b连续存放的这种情况,如果CPU是小端模式,正如我手头的x86机器,我们可以画出栈中数据如下:
     
    低地址image高地址
     
    x表示q指向的一个字符,于是其值就为0x34,y表示q指向的整数,自然就会被解析为0xe0d1234.

    其次是参数传递的问题,腾讯笔试中出现了这么一道题目,代码如下:
    #include <cstdio>
    
    int main(int argc, char **argv)
    
    {
    
    	long long a = 1;
    
    	long long b = 2;
    
    	long long c = 3;
    
    
    
    	printf("%d,%d,%d", a, b, c);
    
    }

    求输出多少?

    首先需要明确的是printf只是解释所指的内存单元里面有些啥,不会强制类型转换,其次long long 类型是64位的,但是我就是傻掉了,以为会强制转换,加上自己不知道long long 类型是个什么类型,所以只好认为会强制转换(虽然潜意识里面第一眼就觉得B:102是答案,最后还是没忍住,改了答案)。然后需要明确的是默认参数入栈顺序是从右至左。有了这个之后我们很容易就能获得栈中的状态:

    低地址(栈顶) %d%d%d
    1 0
    2 0
    3 0
    高地址(栈底)  

    因此可以很清楚地看到答案为102.下面给出另一位仁兄(文章链接)反汇编得出的代码:

    // 从开始执行main函数体内的第一条赋值语句(long long a=1;)开始。
    
    
    
    PUSH EBP     // 保存ebp
    
     MOV EBP,ESP // 设置ebp
    
     SUB ESP,0F0 // 分配栈空间
    
     PUSH EBX    // 保护寄存器 ebx,esi,edi
    
     PUSH ESI
    
     PUSH EDI
    
     LEA EDI,DWORD PTR SS:[EBP-F0] // 将分配的栈空间赋初值,初始化为CCCCCCCC
    
     MOV ECX,3C                    // ecx用作下面rep stos指令的计数器
    
     MOV EAX,CCCCCCCC
    
     REP STOS DWORD PTR ES:[EDI]
    
     MOV DWORD PTR SS:[EBP-C],1   // long long a=1;
    
     MOV DWORD PTR SS:[EBP-8],0
    
     MOV DWORD PTR SS:[EBP-1C],2  // long long b=2;
    
     MOV DWORD PTR SS:[EBP-18],0
    
     MOV DWORD PTR SS:[EBP-2C],3  // long long c=3;
    
     MOV DWORD PTR SS:[EBP-28],0
    
     MOV ESI,ESP
    
     MOV EAX,DWORD PTR SS:[EBP-28] // 参数c入栈
    
     PUSH EAX
    
     MOV ECX,DWORD PTR SS:[EBP-2C]
    
     PUSH ECX
    
     MOV EDX,DWORD PTR SS:[EBP-18] // 参数b入栈
    
     PUSH EDX
    
     MOV EAX,DWORD PTR SS:[EBP-1C]
    
     PUSH EAX
    
     MOV ECX,DWORD PTR SS:[EBP-8]  // 参数a入栈
    
     PUSH ECX
    
     MOV EDX,DWORD PTR SS:[EBP-C]
    
     PUSH EDX
    
     PUSH test4.0041573C // “%d,%d,%d”入栈(0041573C地址开始的位置存放“%d,%d,%d”)
    
     CALL printf // 开始调用printf函数
    
     ADD ESP,1C // 恢复栈地址
    
  • 相关阅读:
    二分图 洛谷P2055 [ZJOI2009]假期的宿舍
    并查集 洛谷P1640 [SCOI2010]连续攻击游戏
    贪心 洛谷P2870 Best Cow Line, Gold
    贪心 NOIP2013 积木大赛
    快速幂 NOIP2013 转圈游戏
    倍增LCA NOIP2013 货车运输
    树形DP 洛谷P2014 选课
    KMP UVA1328 Period
    动态规划入门 BZOJ 1270 雷涛的小猫
    KMP POJ 2752Seek the Name, Seek the Fame
  • 原文地址:https://www.cnblogs.com/obama/p/3027593.html
Copyright © 2011-2022 走看看