随笔misc:大小端字节序互转方法以及栈的生长方向和数组生长方向

判断机器字节序

方法一:强制类型转换

int get_endian()
{
	int a = 0x01;
	char* p = (char*) &a;
	return (*p == 0x01) ? 0 : 1;    /*0: little, 1: big*/
}

方法二:
使用联合体,类似与强转

int get_endian()
{
	union {
		char c;
		int i;
	} a;
	a.i = 0x01;
	return (a.c == 0x01)? 0 : 1;
}

字节序转换

方法一:char*指针强转,需要一个char类型buf来接收

short short_2_big_endian(short parm)
{
	char tmp_buf[2] = {0};
	char *ptr = (char*)&parm;
	if (get_endian() == 0)
	{
		tmp_buf[0] = *(ptr+1);
		tmp_buf[1] = *ptr;
		return *(short*)tmp_buf;
	}
	return parm;
}

方法二:移位操作,无需判断主机大小端

short short_2_big_endian(short parm)
{
	char tmp_buf[2] = {0};
	tmp_buf[0]= (parm >> 0) && 0xff;
	tmp_buf[1]= (parm >> 8) && 0xff;
	return *(short*)tmp_buf;
}

方法三:网络字节序,统统转为大端序,网络字节序为大端序,无需判断主机大小端,但是只能转大端序。

#include <arpa/inet.h>
 
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

有朋友可能会这么想,上面我们用一个char类型的buf来接收字节序转换结果。这个数组是在栈里,栈的生长方向有向下生长和向上生长,如果栈向下生长,那么buf[0]的地址不就比buf[1]的地址大了吗?而arm中栈的生长方向也恰恰是向下生长的,这个理解是十分错误的!!!不管栈向上生长也好向下生长也好,buf[0]的地址都是比buf[1]小的,你打印这两个地址也能发现,看图

在这里插入图片描述
栈的生长方向向下,数组的生长方向向上,栈的顶部是函数调用压的栈帧,当数组越界时,可能会破坏栈帧内容,里面最终要的LR值,也就是后面pop用的PC值破坏,那函数也就没法返回了,一个segment falut就出现了,或者do page fault就出现了,PC值是个不存在的地址,mmu会报错了,程序凉凉。。。

关于数组生长方向的实验

我们先在栈里定义一个char类型的变量a,然后在定义一个数组,然后通过这个数组的索引来改变这个a的值。
见代码:

#include <stdio.h>

int get_array_value(char *array, int index)
{
	return array[index];
}

int main()
{
	char a = 10;
	char buf[5];
	printf("&a:%p, buf:%p, &buf[5]:%p\n", &a, buf, &buf[5]);
	printf("sizeof(buf):%d\n", sizeof(buf));
	for (iint i = 0; i < sizeof(buf); i++)
	{
		buf[i] = i;
	}
	for (int i = 0; i< 1000; i++)
	{

		printf("a:%d, buf[%d]=%d\n", a, i, get_array_value(buf, i));
		if (a == get_array_value(buf, i))
		{
			buf[i] = 11;
			break;
		}
	}
	printf("a after:%d\n", a);
	return 0;
}

执行结果
在这里插入图片描述
打印出三个变量地址,可以看到a的地址是比数组地址buf多7的,后面实验也是一样buf[7]就是a的值了。我们通过修改buf[7]的值,a的值也随之改变。
变量在栈里的情况:
在这里插入图片描述
我们是紧连着分配的a和buf,但是在栈中,他们是没有紧连在一起的,中间还隔着两个字节。a不是buf[5]而是buf[7],这是因为,栈的增长是按4自己对齐的,也就是说sp的增长只能是,sub sp , sp, #4 (#8,#12…)
而a和buf一共占用6个字节,所以sp一次增长8(栈向下生长,表现为sp减少),而a是从栈顶开始分配,所以位置为栈最高的位置,而数组地址可能是对齐的要求,所以分配到了最底端,中间就空了两个字节,实际上如果在a和buf中间再分配两个char,栈地大小也是这样的,刚好填充了中间的两个字节。来看看汇编代码吧,汇编中变量的地址是用[sp #-12]类似的间接寻址的 ,整数赋值用str命令,char型用strb命令。

00010440 <get_array_value>:
   10440:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   10444:	e28db000 	add	fp, sp, #0
   10448:	e24dd00c 	sub	sp, sp, #12
   1044c:	e50b0008 	str	r0, [fp, #-8]
   10450:	e50b100c 	str	r1, [fp, #-12]
   10454:	e51b300c 	ldr	r3, [fp, #-12]
   10458:	e51b2008 	ldr	r2, [fp, #-8]
   1045c:	e0823003 	add	r3, r2, r3
   10460:	e5d33000 	ldrb	r3, [r3]
   10464:	e1a00003 	mov	r0, r3
   10468:	e28bd000 	add	sp, fp, #0
   1046c:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
   10470:	e12fff1e 	bx	lr

00010474 <main>:
   10474:	e92d4810 	push	{r4, fp, lr}        /*push命令,并不会使sp减少*/
   10478:	e28db008 	add	fp, sp, #8
   1047c:	e24dd014 	sub	sp, sp, #20        /*分配栈,其中12字节是栈帧(r4,fp,lr), 变量可用大小只有8字节*/
   10480:	e3a0300a 	mov	r3, #10
   10484:	e54b3011 	strb	r3, [fp, #-17]	; 0xffffffef       /*a 赋值*/
   10488:	e3a03000 	mov	r3, #0
   1048c:	e50b3010 	str	r3, [fp, #-16]
   10490:	e24b3018 	sub	r3, fp, #24
   10494:	e2833005 	add	r3, r3, #5
   10498:	e24b2018 	sub	r2, fp, #24
   1049c:	e24b1011 	sub	r1, fp, #17
   104a0:	e3000630 	movw	r0, #1584	; 0x630
   104a4:	e3400001 	movt	r0, #1
   104a8:	ebffff8f 	bl	102ec <printf@plt>
   104ac:	e3a01005 	mov	r1, #5
   104b0:	e300064c 	movw	r0, #1612	; 0x64c
   104b4:	e3400001 	movt	r0, #1
   104b8:	ebffff8b 	bl	102ec <printf@plt>
   104bc:	e3a03000 	mov	r3, #0
   104c0:	e50b3010 	str	r3, [fp, #-16]
   104c4:	ea000009 	b	104f0 <main+0x7c>
   104c8:	e51b3010 	ldr	r3, [fp, #-16]
   104cc:	e6ef1073 	uxtb	r1, r3
   104d0:	e24b2018 	sub	r2, fp, #24
   104d4:	e51b3010 	ldr	r3, [fp, #-16]
   104d8:	e0823003 	add	r3, r2, r3
   104dc:	e1a02001 	mov	r2, r1
   104e0:	e5c32000 	strb	r2, [r3]
   104e4:	e51b3010 	ldr	r3, [fp, #-16]
   104e8:	e2833001 	add	r3, r3, #1
   104ec:	e50b3010 	str	r3, [fp, #-16]
   104f0:	e51b3010 	ldr	r3, [fp, #-16]
   104f4:	e3530004 	cmp	r3, #4
   104f8:	9afffff2 	bls	104c8 <main+0x54>
   104fc:	e3a03000 	mov	r3, #0
   10500:	e50b3010 	str	r3, [fp, #-16]
   10504:	ea00001d 	b	10580 <main+0x10c>
   10508:	e55b3011 	ldrb	r3, [fp, #-17]	; 0xffffffef
   1050c:	e1a04003 	mov	r4, r3
   10510:	e24b3018 	sub	r3, fp, #24
   10514:	e51b1010 	ldr	r1, [fp, #-16]
   10518:	e1a00003 	mov	r0, r3
   1051c:	ebffffc7 	bl	10440 <get_array_value>
   10520:	e1a03000 	mov	r3, r0
   10524:	e51b2010 	ldr	r2, [fp, #-16]
   10528:	e1a01004 	mov	r1, r4
   1052c:	e300065c 	movw	r0, #1628	; 0x65c
   10530:	e3400001 	movt	r0, #1
   10534:	ebffff6c 	bl	102ec <printf@plt>
   10538:	e55b3011 	ldrb	r3, [fp, #-17]	; 0xffffffef
   1053c:	e1a04003 	mov	r4, r3
   10540:	e24b3018 	sub	r3, fp, #24
   10544:	e51b1010 	ldr	r1, [fp, #-16]
   10548:	e1a00003 	mov	r0, r3
   1054c:	ebffffbb 	bl	10440 <get_array_value>
   10550:	e1a03000 	mov	r3, r0
   10554:	e1540003 	cmp	r4, r3
   10558:	1a000005 	bne	10574 <main+0x100>
   1055c:	e24b2018 	sub	r2, fp, #24
   10560:	e51b3010 	ldr	r3, [fp, #-16]
   10564:	e0823003 	add	r3, r2, r3
   10568:	e3a0200b 	mov	r2, #11
   1056c:	e5c32000 	strb	r2, [r3]
   10570:	ea000005 	b	1058c <main+0x118>
   10574:	e51b3010 	ldr	r3, [fp, #-16]
   10578:	e2833001 	add	r3, r3, #1
   1057c:	e50b3010 	str	r3, [fp, #-16]
   10580:	e51b3010 	ldr	r3, [fp, #-16]
   10584:	e3530ffa 	cmp	r3, #1000	; 0x3e8
   10588:	baffffde 	blt	10508 <main+0x94>
   1058c:	e51b1010 	ldr	r1, [fp, #-16]
   10590:	e3000670 	movw	r0, #1648	; 0x670
   10594:	e3400001 	movt	r0, #1
   10598:	ebffff53 	bl	102ec <printf@plt>
   1059c:	e55b3011 	ldrb	r3, [fp, #-17]	; 0xffffffef
   105a0:	e1a01003 	mov	r1, r3
   105a4:	e3000678 	movw	r0, #1656	; 0x678
   105a8:	e3400001 	movt	r0, #1
   105ac:	ebffff4e 	bl	102ec <printf@plt>
   105b0:	e3a03000 	mov	r3, #0
   105b4:	e1a00003 	mov	r0, r3
   105b8:	e24bd008 	sub	sp, fp, #8
   105bc:	e8bd8810 	pop	{r4, fp, pc}

tips:push,pop命令并不会使sp改变,需要我们手动改变sp的值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值