You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

位域结构体存储的32位指令转换为小端十六进制输出问题

问题描述

我需要将32位指令转换为机器码二进制,示例指令add #3, #5, #9的参数如下:

  • opcode为0
  • rs取第一个操作数值3,rt取第二个操作数值5,rd取第三个操作数值9
  • funct值为1
  • 未使用的6位统一填0
  • #x代表内存中的寄存器

因此上述R型指令的二进制表示为:

opCode rs rt rd funct unused
000001 00011 00101 01001 00001 000000,即32位/4字节指令


我当前使用以下联合体定义存储各类型指令:

typedef union __attribute__((__packed__))
{
    struct
    {
        unsigned opcode : 6;
        unsigned rs : 5;
        unsigned rt : 5;
        unsigned rd : 5;
        unsigned funct : 5;
        unsigned unused : 6;
    } r;
    struct
    {
        unsigned first : 8;
        unsigned second : 8;
        unsigned third : 8;
        unsigned fourth : 8;
    } bytes;
} r_instruction;

typedef union __attribute__((__packed__))
{

    struct
    {

        unsigned rs : 5;
        unsigned rt : 5;
        unsigned opcode : 6;
        unsigned immed : 16;
    } i;
    struct
    {
        unsigned first : 8;
        unsigned second : 8;
        unsigned third : 8;
        unsigned fourth : 8;
    } bytes;
} i_instruction;

typedef union __attribute__((__packed__))
{
    struct
    {
        unsigned addr : 25;
        unsigned opcode : 6;
        unsigned isReg : 1;
    } j;
    struct
    {
        unsigned first : 8;
        unsigned second : 8;
        unsigned third : 8;
        unsigned fourth : 8;
    } bytes;
} j_instruction;

我的需求是将每条指令的二进制输出到文件,每行对应一条指令的4字节,每个字节以十六进制表示,字节序为小端。
待处理的输入汇编代码如下:

;comment
MAIN: add       #3, #5,     #9
LOOP: ori        #9, -5, #2
      la    val1
      jmp   Next
Next: move  #20, #4
      bgt   #0, #2, END
      la    K
      sw    #0, 4, #10
      bne   #31, #9     , LOOP
      call  val1
      jmp   #4
END:  stop 
STR:  .asciz    "aBcd"
LIST: .db   6, -9
      .dh   27056
      .dw   5
.entry K   
K:     .dw 31,-12
.extern     val1

我按照如下方式输出时得到的结果不符合预期:

r_instruction inst;
inst.r.opcode = 0;
inst.r.rs = 3;
inst.r.rt = 5;
inst.r.rd = 9;
inst.r.funct = 1;
inst.r.unused = 0;
printf("%x %x %x %x", inst.bytes.first, 
    inst.bytes.second, 
    inst.bytes.third, inst.bytes.fourth);
// 输出结果为 c0 28 29 0

请问我应该如何修改,才能将存储的指令转换为要求的输出格式?


解决方案

你遇到的问题核心是C语言位域的分配顺序和你预期的指令字段排列顺序不符,小端架构下,编译器会从结构体低地址的最低位开始分配位域,你当前写的位域顺序是从高位到低位排列,和实际分配规则完全相反。

第一步:修正所有指令的位域定义顺序

你需要把位域按照「从最低位到最高位」的顺序倒着写,和你之前的定义顺序反过来:

  1. R型指令原预期的字段排列(高位到低位)是opcode -> rs -> rt -> rd -> funct -> unused,对应位域定义要反过来(低位到高位):
struct
{
    unsigned unused : 6; // 最低6位
    unsigned funct : 5;
    unsigned rd : 5;
    unsigned rt : 5;
    unsigned rs : 5;
    unsigned opcode : 6; // 最高6位
} r;
  1. I型指令、J型指令同理,把你定义的结构体字段顺序完全倒转即可。

第二步:修正输出格式

你当前的printf没有补前导零,会导致小于0x10的字节只输出1位,不符合要求,修改输出语句为:

printf("%02x %02x %02x %02x\n", inst.bytes.first, 
    inst.bytes.second, 
    inst.bytes.third, inst.bytes.fourth);

%02x表示输出两位十六进制,不足的位置前面补0。

修正后再运行代码,输出结果就会符合小端字节序的要求。


内容的提问来源于stack exchange,提问作者best man

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 22:48:03