【问题标题】:How do I deal with negative numbers in C?我如何处理 C 中的负数?
【发布时间】:2022-11-26 21:54:52
【问题描述】:

我正在尝试用 C 编写一种非常基本的汇编语言。 每条指令有 32 位,前 8 位是操作码,接下来的 24 位包含一个立即值(如果指令带有一个。否则它只是零)。 操作码被定义为简单的数字。例如 PUSHC 被定义为 1

现在我想测试操作码和立即值是否可以正确分离。

我写了以下定义:

#define SIGN_EXTEND(i) ((i) & 0x00800000 ? (i) | 0xFF000000 : (i))      // Handles negative Immediate Values (i)
#define IMMEDIATE(x) SIGN_EXTEND(x & 0x00FFFFFF)                        // Returns the Immediate Value of an instruction (x)
#define OPCODE(x) (x >> 24)                                             // Returns the Opcode of an instruction (x)
#define OP(o) ((o) << 24)                                               // An instruction with an Opcode (o)
#define OPI(o, i) (OP(o) | IMMEDIATE(i))                                // An instruction with an Opcode (o) and an Immediate Value (i)

void runProg(uint32_t prog[]) {...} 方法中,我传递了一个包含汇编程序指令的数组,按顺序用逗号分隔,如下所示:

uint32_t progTest[] = {OPI(PUSHC, 3), OPI(PUSHC, 4}, OP(ADD), OP(HALT)};
runProg(progTest);

这是 runProg 所做的:

void runProg(uint32_t prog[]) {
    int pc = -1;            // the program counter
    uint32_t instruction;

    do {
        pc++;
        instruction = prog[pc];
        printf("Command %d : 0x%08x -> Opcode [%d] Immediate [%d]\n",
               pc, instruction, OPCODE(instruction), IMMEDIATE(instruction));
    } while (prog[pc] != OP(HALT));

}

所以它以十六进制形式打印出完整的命令,然后是操作码,然后是立即值。这适用于我定义的所有指令。上面的测试程序给出了这个输出:

Command 0 : 0x01000003 -> Opcode [1] Immediate [3]
Command 1 : 0x01000004 -> Opcode [1] Immediate [4]
Command 2 : 0x02000000 -> Opcode [2] Immediate [0]
Command 3 : 0x00000000 -> Opcode [0] Immediate [0]

现在问题来了:

命令PUSHC 仅适用于正值。 将第一个 PUSHC 调用的立即值更改为 -3 会产生以下结果:

Command 0 : 0xfffffffd -> Opcode [255] Immediate [-3]
Command 1 : 0x01000004 -> Opcode [1] Immediate [4]
Command 2 : 0x02000000 -> Opcode [2] Immediate [0]
Command 3 : 0x00000000 -> Opcode [0] Immediate [0]

正如您所看到的,即时值显示正确,但是该命令缺少操作码。

更改IMMEDIATE(x)的定义 从

#define IMMEDIATE(x) SIGN_EXTEND(x & 0x00FFFFFF)

#define IMMEDIATE(x) (SIGN_EXTEND(x) & 0x00FFFFFF)

产生完全相反的结果,其中 Opcode 被正确分隔,但立即值是错误的:

Command 0 : 0x01fffffd -> Opcode [1] Immediate [16777213]
Command 1 : 0x01000004 -> Opcode [1] Immediate [4]
Command 2 : 0x02000000 -> Opcode [2] Immediate [0]
Command 3 : 0x00000000 -> Opcode [0] Immediate [0]

因此,我比较确定我对SIGN_EXTEND(i)的定义是有缺陷的。但是,我似乎无法确定。

非常感谢有关如何解决此问题的任何想法!

【问题讨论】:

  • OPI 用负立即值破坏操作码

标签: c


【解决方案1】:

0x01fffffd是正确的; 8位操作码域包含0x01,24位立即数域包含0xfffffd,即-3的24位二进制补码编码。编码时,无需符号扩展; IMMEDIATE 宏被传递了一个(大概)32 位的二进制补码值,它的工作只是将它减少到 24 位,而不是扩展它。所以它只需要是#define IMMEDIATE(x) ((x) &amp; 0xffffff)。当你想解释立即字段,至于打印,那么你需要从 24 位转换为 32 位。为此,你需要一个不同的宏,就像你有不同的宏来编码操作代码(OPI)和解码/提取/解释操作代码 (OPCODE)。

您可以使用此函数解释立即字段:

static int InterpretImmediate(unsigned x)
{
    //  Extract the low 24 bits.
    x &= (1u<<24) - 1;

    /*  Flip the sign bit.  If the sign bit is 0, this
        adds 2**23.  If the sign bit is 1, this subtracts 2**23.
    */
    x ^= 1u<<23;

    /*  Convert to int and subtract 2**23.  If the sign bit started as 0, this
        negates the 2**23 we added above.  If it started as 1, this results in
        a total subtraction of 2**24, which produces the two’s complement of a
        24-bit encoding.
    */
    return (int) x - (1u<<23);
}

【讨论】:

    【解决方案2】:

    您认为 SIGN_EXTEND 存在缺陷是对的。我建议您检查 ? 三元和 &amp; 二元和运算符的优先级,并添加更多括号以更明确地说明您要放入 ? 的条件中的内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-28
      • 2022-09-28
      • 1970-01-01
      • 1970-01-01
      • 2017-07-10
      • 2019-04-06
      相关资源
      最近更新 更多