【问题标题】:C Pointer manipulation in switch statementswitch 语句中的 C 指针操作
【发布时间】:2015-12-05 04:32:38
【问题描述】:

大家好,我尝试编写一个简单的 switch 语句并遇到了这个问题。 我无法弄清楚为什么这段代码可以正常工作,我想这是因为运算符 ** 和 ++ 的优先级。 如果是这种情况,如果有人能写一个例子我应该如何在下面的语句中使用 value-at * 和 inc/dec 运算符,我会很高兴。

提前致谢,

while (--argc > 0) 
        argv++;
        switch (**argv) 

这段代码没有

while (--argc > 0) 
        switch (**(argv++)) 

完整代码:

while (--argc > 0) {
        switch (**(argv++)) {
        case '\0':
            panic("empty command line argument");
            break;
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            push (atof(*argv));
            break;
        case '+':
            push(pop() + pop());
            break;
        case '-':
            op2 = pop();
            push(pop() - op2);
            break;
        case '*':
            push(pop() * pop());
            break;
        case '/':
            op2 = pop();
            push(pop() / op2);
            break;
        default:
            panic("unknown command");
            break;
        }
    }

【问题讨论】:

标签: c operator-precedence post-increment


【解决方案1】:

在任何表达式中对给定变量使用后自增会导致变量在表达式被计算之后自增。

正如您的第一个工作代码所述,您增加argv在开关中获得它的引用值,您希望变量在之前增加您的表达式已被评估,因此您需要使用预增量:

while (--argc > 0) 
        switch (**(++argv)) 

【讨论】:

  • 那是糟糕的代码——人类的认知限制将人类大脑在任何时候可以跟踪的事物数量限制在大约 5 到 7 件事。所有那些塞进两行的运算符都会产生令人讨厌的错误,这些错误几乎是不可能弄清楚的。见en.wikipedia.org/wiki/…
  • 我同意你的看法,但这是 OP 要求的结构,我的工作不是在这里猜测他为什么或为什么不需要它。
  • 内括号是多余的。
  • @ManuelMiranda 非常感谢 Manuel,我把自己弄糊涂了,没有注意这个小细节,谢谢。
【解决方案2】:

我认为您对括号感到困惑。括号会影响计算顺序,但您使用的是后增量,无论运算符的计算顺序如何,都会在末尾应用。

在你的第一个 sn-p 中,顺序很明确:首先你增加 argv,然后你取消引用它。也就是说,您取消引用“下一个”元素,而不是当前元素。

在您的第二个 sn-p 中,您希望获得相同的结果,并且您正在玩括号。这不是解决方案。括号会影响 2 个运算符(++**)的求值顺序,但这并不意味着效果会按该顺序应用。

例如:如果你写了

switch ((**argv)++)

编译器会先应用**,解引用,给你内容,然后再应用++(显然argv必须是可以增加的数据类型,否则会报错,但在这里没关系)。相反,如果你像以前那样写作,

switch (**(argv++))

首先应用增量 (++),然后应用间接 (**)。但诀窍是:后增量仍然是后增量。在这里应用后增量意味着:取 current 值,当一切完成后记得增加它。所以argv 原样使用,没有增加它(还),并发送到**,这将给出 current 值(不是下一个!)。然后,在switch 读取当前元素后,argv 会增加(后增量),因此如果您的cases 打印了**argv,您会注意到它是“下一个”值。

一个解决方案是使用预增量:

switch (**(++argv))

但如果你问我,真正的解决方案是完全避免这些令人头疼的问题,并在 2 行单独的行中编写代码,这样发生的事情就一目了然了。正如你在第一个 sn-p 中所做的那样。这是最易读的风格,因此应该是首选。然后你可以忘记一切:评估顺序、括号、前后增量、关联性。

【讨论】:

  • 去掉多余的内括号,让代码更简洁。
  • @EOF 删除括号确实会删除一些混乱,但是很难理解运算符的评估顺序。我认为总而言之它的可读性会更少
  • 如果他不想要更短的代码,OP 可能不会问这个问题。我觉得他应该如愿以偿(无论这可能有多么可疑)。
猜你喜欢
  • 2021-12-11
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 2021-04-09
相关资源
最近更新 更多