测试下联合体访问数据和左移访问数据的区别
源码(结构体)
联合体
#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"
赋值命令数量相同。但是数组初始化时比联合体数组长了些。