1. 程式人生 > 其它 >測試下聯合體訪問資料和左移訪問資料的區別

測試下聯合體訪問資料和左移訪問資料的區別

原始碼(結構體)

聯合體

#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"

賦值命令數量相同。但是陣列初始化時比聯合體陣列長了些。