【问题标题】:Which part of this C code is missing or needs to be altered?此 C 代码的哪一部分丢失或需要更改?
【发布时间】:2016-03-31 07:10:29
【问题描述】:

对于我的作业,我必须填写以下 C 代码的缺失部分。 但是,我不确定缺少哪些部分或必须填写哪些部分。 我有一个该代码将生成的示例汇编代码,但不知道我必须更改哪些部分才能获得预期的结果。我只是想澄清一下。

typedef enum {MODE_A, MODE_B, MODE_C, MODE_D, MODE_E} mode_t;
long switch3 (long *p1, long *p2, mode_t action) {
  long result = 0;
  switch(action){
  case MODE_A:
  case MODE_B:
  case MODE_C:
  case MODE_D:
  case MODE_E:
  default;
  }
  return result;
}

其他要点:

  • 可能有一些情况应该写在 C 中 带有失败的代码
  • 代码显示开关中枚举类型值的分支 陈述。 (问题:简单来说这到底是什么意思?我的教授提供了一个我不明白的复杂定义。)

汇编代码结果示例:

# p1 in %rdi, p2 in %rsi, action in %edx
.L2:                         # MODE_E
      movl    $27, %eax
      ret
.L7:                         # MODE_A
      movl    (%rsi), %rax
      movq    (%rdi), %rdx
      movq     %rdx, (%rsi)
      ret
.L5:                         # MODE_B
      movq     (%rdi), %rax
      addq     (%rsi), %rax
      movq      %rax, (%rdi)
      ret
.L4:                         # MODE_C
      movq     $59, (%rdi)
      movq     (%rsi), %rax
      ret
.L3:                         # MODE_D
      movq     (%rsi), %rax
      movq      %rax, (%rdi)
      movl      $27, %eax
      ret
.L8:                         # default
      movl      $12, %eax
      ret

【问题讨论】:

  • “在 switch 语句中对枚举类型值进行分支”表示switch(action),其中action 是一个枚举
  • 你将不得不解释你的预期结果是什么
  • ...我的任务 - 完全正确。 你的。查看程序集,了解逻辑结构,并确定如何在 C 中执行以获得相同的结构。
  • 在汇编代码中,每个case的末尾都有一个ret,所以没有case应该写在C代码中。
  • 旁注#2:为什么对这个问题投反对票???这就是我不再在这里发布问题的原因。这个网站上有太多聪明的@$$es。

标签: c assembly switch-statement


【解决方案1】:

因为这是一个任务,我不会给你代码。但这里对这两点进行澄清。

switch() case通常可以被视为一个块,例如:

if(myvar == ...){
    //branch1
} else if(myvar == ...){
    //branch2
}
...

每个if 都是一个分支,在您的情况下,每个分支条件都取决于一个枚举值。那应该回答branching on an enumerated type value in a switch statement 的问题。

我写“一般”是因为,事实上switch case 更像是一个asm jump if equals。所以一旦它到达正确的case,下面的所有代码都会被执行,甚至是下一个casestatements 中的代码。您必须通过以编程方式停止 switch 块来处理此问题(您要么破坏它,要么返回)。这是fall-through 点。

您可以找到很多解释 switch case 工作原理的网站。

现在你必须用正确的实现填充每个case——它似乎是排列。

【讨论】:

  • @Prosze 请注意,默认情况下不需要break。 (把它放在那里并没有什么坏处,很多人都这样做;我没有,不重要,只是偏好)。
  • @RastaJedi,但如果默认情况不是最后一个,你确实需要它:)
  • 是的,@StoryTeller 是对的;无论哪种情况是最后一种,都不一定需要break
  • @RastaJedi,实际上不仅仅是偏好。代码可以改变和移动,一个开关可以重组。如果您喜欢我,请为此复制和粘贴,缺少的休息可能会丢失,and you'll end up with a bug in your code
  • @RastaJedi,他们还没有创建可以保护您免受人为错误的 Vim 插件。当他们这样做时,请告诉我。我将不再过于谨慎。
【解决方案2】:

这不是很清楚。但据我了解,教授提供了一个汇编代码和一个 C 代码
我认为他希望你以这种方式扩展 C 代码,编译它会产生类似于他提供的汇编代码。

我希望我没有搞砸(我在阅读 AT&T 语法时遇到了重大问题),但对我来说这看起来像:

typedef enum {MODE_A, MODE_B, MODE_C, MODE_D, MODE_E} mode_t;
long switch3 (long *p1, long *p2, mode_t action) {
  long result = 0;
  switch(action){
    case MODE_A:  result = *p2; *p2 = *p1; break;
    case MODE_B:  result = *p2; *p1 = *p1 + *p2; break;
    case MODE_C:  result = *p2; *p1 = 59; break;
    case MODE_D: *p1 = *p2;  // fallthru to E
    case MODE_E: result = 27 break;
    default: result = 12;
  }
  return result;
}

“可能有一些情况应该用 C 代码写成一个失败”对我来说是一个提示

    case MODE_D: *p1 = *p2;  // fallthru to E
    case MODE_E: result = 27 break;

应该写,而不是

    case MODE_D: *p1 = *p2;  result = 27 break;
    case MODE_E: result = 27 break;

(结果相同)即使编译器为此选择了另一个标签

【讨论】:

  • 您绝对应该在每个case 的末尾(或switch 语句的末尾)添加return result
  • 如果你查看 OPs 帖子中的代码,你可以看到这是在 switch 之后完成的,我只是更改了 switch 语句,而不是整个函数
  • 但显然这并不明显,我会扩展答案以涵盖完整的原始 c 代码
  • 啊好吧,创建的代码总是 100% 代表创建它的代码?我怀疑教授指向fallthroug,如果没有... asm 也不代表(不需要的)“结果”变量,该变量在 asm 中被优化,但存在于 C 代码中。 asm 没有退出开关,而是退出函数。另一个提示是编译器将“MODE_E”重新排列为第一种情况
  • 将 .L2 标签直接放在 .L3 之后的“movl $27, %eax”之前会在汇编程序中实现相同的“功能”......这没什么神奇的
猜你喜欢
  • 2012-08-25
  • 2015-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 2021-05-27
相关资源
最近更新 更多