測試下聯合體訪問資料和左移訪問資料的區別
阿新 • • 發佈:2022-02-23
原始碼(結構體)
聯合體
#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"
賦值命令數量相同。但是陣列初始化時比聯合體陣列長了些。