测试下联合体访问数据和左移访问数据的区别

源码(结构体)

联合体

#include <stdio.h>
#include <stdint.h>
typedef struct{
union data
{
    uint16_t value;
    uint8_t addr[2];
    /* data */
}data;

}reg;
reg REG={0};
int a,b;
int main()
{
    REG.data.value=0x1234;
    a=REG.data.addr[1];
    b=REG.data.addr[0];
    return 0;
}

位操作

#include <stdio.h>
#include <stdint.h>
typedef struct{
uint16_t data;

}reg;
reg REG={0};
int a,b;
int main()
{
    REG.data=0x1234;
	a=(REG.data)>>8&0xff;
    b=REG.data&0xff;
    return 0;
}

汇编对应

初始化

在生成REG结构体时,汇编代码完全一致

REG:
	.space 2
	.comm	a, 4, 2
	.comm	b, 4, 2
	.def	__main;	.scl	2;	.type	32;	.endef
	.text
	.globl	main
	.def	main;	.scl	2;	.type	32;	.endef
	.seh_proc	main
REG:
	.space 2
	.comm	a, 4, 2
	.comm	b, 4, 2
	.def	__main;	.scl	2;	.type	32;	.endef
	.text
	.globl	main
	.def	main;	.scl	2;	.type	32;	.endef
	.seh_proc	main

赋值给REG,都使用了

movw	$4660, REG(%rip)

在赋值给a时,发生了区别

	movzbl	1+REG(%rip), %eax
	movzbl	%al, %edx
	leaq	a(%rip), %rax
	movzwl	REG(%rip), %eax
	shrw	$8, %ax
	movzwl	%ax, %eax
	movzbl	%al, %edx
	leaq	a(%rip), %rax

使用联合体时,直接读取高8位字节赋值给a;

使用位操作会移动整个reg到%eax寄存器,然后左移8位,再将%ax写入%eax寄存器,最后在赋值给a;

在这里多执行了两条命令。

赋值给b

	movzbl	REG(%rip), %eax
	movzbl	%al, %edx
	leaq	b(%rip), %rax
	movzwl	REG(%rip), %eax
	movzwl	%ax, %eax
	movzbl	%al, %edx
	leaq	b(%rip), %rax

也多执行了一条命令。

源码(数组)

#include <stdio.h>
#include <stdint.h>
union data
{
    uint16_t value;
    uint8_t addr[2];
    /* data */
}REG[16];

int a,b;
int main()
{
    REG[0].value=0x1234;
    a=REG[0].addr[1];
    b=REG[0].addr[0];
    return 0;
}
#include <stdio.h>
#include <stdint.h>
uint16_t REG[16]={0};
int a,b;
int main()
{
    REG[0]=0x1234;
   a=REG[0]>>8&0xff;
    b=REG[0]&0xff;
    return 0;
}

汇编对应

	.file	"struct.c"
	.text
	.comm	REG, 32, 5
	.comm	a, 4, 2
	.comm	b, 4, 2
	.def	__main;	.scl	2;	.type	32;	.endef
	.globl	main
	.def	main;	.scl	2;	.type	32;	.endef
	.seh_proc	main
main:
	pushq	%rbp
	.seh_pushreg	%rbp
	movq	%rsp, %rbp
	.seh_setframe	%rbp, 0
	subq	$32, %rsp
	.seh_stackalloc	32
	.seh_endprologue
	call	__main
	leaq	REG(%rip), %rax
	movw	$4660, (%rax)
	leaq	REG(%rip), %rax
	movzbl	1(%rax), %eax
	movzbl	%al, %edx
	leaq	a(%rip), %rax
	movl	%edx, (%rax)
	leaq	REG(%rip), %rax
	movzbl	(%rax), %eax
	movzbl	%al, %edx
	leaq	b(%rip), %rax
	movl	%edx, (%rax)
	movl	$0, %eax
	addq	$32, %rsp
	popq	%rbp
	ret
	.seh_endproc
	.ident	"GCC: (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 8.1.0"

.file	"code.c"
	.text
	.globl	REG
	.bss
	.align 32
REG:
	.space 32
	.comm	a, 4, 2
	.comm	b, 4, 2
	.def	__main;	.scl	2;	.type	32;	.endef
	.text
	.globl	main
	.def	main;	.scl	2;	.type	32;	.endef
	.seh_proc	main
main:
	pushq	%rbp
	.seh_pushreg	%rbp
	movq	%rsp, %rbp
	.seh_setframe	%rbp, 0
	subq	$32, %rsp
	.seh_stackalloc	32
	.seh_endprologue
	call	__main
	movw	$4660, REG(%rip)
	movzwl	REG(%rip), %eax
	shrw	$8, %ax
	movzwl	%ax, %eax
	movzbl	%al, %edx
	leaq	a(%rip), %rax
	movl	%edx, (%rax)
	movzwl	REG(%rip), %eax
	movzwl	%ax, %eax
	movzbl	%al, %edx
	leaq	b(%rip), %rax
	movl	%edx, (%rax)
	movl	$0, %eax
	addq	$32, %rsp
	popq	%rbp
	ret
	.seh_endproc
	.ident	"GCC: (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 8.1.0"

赋值命令数量相同。但是数组初始化时比联合体数组长了些。

posted @ 2022-02-23 18:09  USTHzhanglu  阅读(50)  评论(0编辑  收藏  举报