是否有使用不带大括号的 switch 语句的有用案例?

发布于 2024-12-15 11:35:35 字数 729 浏览 2 评论 0原文

在 H&S5 中,我遇到了“最奇怪的”switch 语句(8.7.1,第 277 页),它没有使用大括号。
示例如下:

switch (x)
    default:
    if (prime(x))
        case 2: case 3: case 5: case 7:
            process_prime(x);
    else
        case 4: case 6: case 8: case 9: case 10:
            process_composite(x);

这个想法似乎是为了避免最常见的小数字的 prime(x) 开销。

当我看到该声明时,我对缺少的大括号感到困惑,但检查了官方语法(C1X 预标准,6.8.4,第 147 页),语法是正确的:switch 语句在 switch 表达式和右括号之后只有一个语句。

但在我的编程实践中,我再也没有遇到过这样一个奇怪的 switch 语句(我不想在代码中看到任何我必须负责的语句),但我开始想知道:

你们中有人知道这样的 switch 表达式吗?一个不使用大括号但仍然有意义的?不仅仅是 switch (i); (这是合法的,但是是 NOP),而是至少使用两个具有某种有用目的的 case 标签?

In H&S5 I encountered the "most bizarre" switch statement (8.7.1, p. 277) not using braces.
Here's the sample:

switch (x)
    default:
    if (prime(x))
        case 2: case 3: case 5: case 7:
            process_prime(x);
    else
        case 4: case 6: case 8: case 9: case 10:
            process_composite(x);

The idea seems to be to avoid the overhead of prime(x) for the most common small numbers.

When I saw that statement, I was confused about the missing braces, but checking the official grammar (C1X pre-standard, 6.8.4, p. 147), the syntax was correct: A switch statement just has a statement after the switch expression and the closing parenthesis.

But in my programming practice I never again encountered such a curious switch statement (and I wouldn't want to see any in code that I have to take responsibility for), but I started wondering:

Would any of you know such a switch expression, one without using braces, but still having meaning? Not just switch (i); (which is legal, but a NOP), but using at least two case labels having some sort of useful purpose?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

夏天碎花小短裙 2024-12-22 11:35:35

如果您在宏中使用控制结构,则使用 switch 而不是 if 会很方便,因为它没有悬空的 else 问题。

#define DEBUG_PRINT(...) switch (!debug_mode) case 0: fprintf(__VA_ARGS__)

这样,如果该宏的用户将其置于附加条件中,您就不会感到惊讶。

if (unclear) DEBUG_PRINT(stderr, "This is really %unclear\n", unclear);
else {
 // do something reasonable here
}

这样的调试宏具有始终被编译(然后最终被优化)的优点。因此,调试代码必须在程序的整个生命周期内保持有效。

另请注意,switch 不使用 {},这一点很重要,否则 if/else 示例也将无法工作。所有这些都可以通过其他方式来实现(if/else(void)0do/while 技巧),但这是最重要的我知道的方便。

不要误会我的意思,我并不是说每个人都应该在宏内使用控制结构,您当然应该知道自己在做什么。但在某些情况下这是合理的。

If you use control structures in macros a switch instead of if comes handy since it has no dangling else problem.

#define DEBUG_PRINT(...) switch (!debug_mode) case 0: fprintf(__VA_ARGS__)

With that you don't have surprises if a user of that macro puts this in an additional condition

if (unclear) DEBUG_PRINT(stderr, "This is really %unclear\n", unclear);
else {
 // do something reasonable here
}

Such a debug macro has the advantage of being always compiled (and then eventually optimized out). So the debug code has to remain valid through all the live time of the program.

Also observe here that it is important that the switch doesn't use {}, otherwise the if/else example wouldn't work either. All this could be achieved by other means (if/else , (void)0 and do/while tricks) but this one is the most convenient I know of.

And don't take me wrong, I don't say that everybody should use control structures inside macros, you certainly should know what you are doing. But there are situations where it is justified.

旧故 2024-12-22 11:35:35

这是 Dennis Ritchie 于​​ 1972 年在 他的第一个研究工作期间编写的示例C 编译器。 c02.c 模块链接在我刚刚链接到的页面底部,包括

easystmt()
{
    extern peeksym, peekc, cval;

    if((peeksym=symbol())==20)  /* name */
        return(peekc!=':');  /* not label */
    if (peeksym==19) {      /* keyword */
        switch(cval)
        case 10:    /* goto */
        case 11:    /* return */
        case 17:    /* break */
        case 18:    /* continue */
            return(1);
        return(0);
    }
    return(peeksym!=2);     /* { */
}

从阅读他 1972 年的代码可以看出,Dennis 是 switch 语句的粉丝 - 他经常使用它们。鉴于几乎所有内容都被编码为 int ,部分原因是缺乏其他数据类型的可能性,这并不奇怪。他的编译器实现在那个阶段没有使用结构,因为他刚刚将它们添加到语言中。动态调度、虚函数表和多态性还有很长的路要走。我尝试过但未能找到这方面的参考资料,但如果我没记错的话,丹尼斯“发明了”switch 语句,或者至少贡献了导致它们在 C 中采用的形式的想法,并且认为它们是他最好或最自豪的补充之一语言

省略大括号的能力使得 switch 语句在形式上类似于 iffordowhile 语句,有助于简化和统一语法。请参阅 C 语法中的选择语句和迭代语句产生式(例如,在 Kernighan 和 Ritchie 的附录 A13 中,我的副本中的第 236-237 页),其中定义了这些内容。

显然,人们总是可以添加大括号,但对于像这样简单的例子来说,这似乎很沉重。这个示例可以编码为析取 if 语句,但我认为 Dennis 对于 switch 的想法之一是,编译器更清楚地有机会根据所涉及的特定常量来优化分支逻辑的实现。

Here's an example written by Dennis Ritchie in 1972 during his work on the first C compiler. The c02.c module, linked at the foot of page I just linked to, includes

easystmt()
{
    extern peeksym, peekc, cval;

    if((peeksym=symbol())==20)  /* name */
        return(peekc!=':');  /* not label */
    if (peeksym==19) {      /* keyword */
        switch(cval)
        case 10:    /* goto */
        case 11:    /* return */
        case 17:    /* break */
        case 18:    /* continue */
            return(1);
        return(0);
    }
    return(peeksym!=2);     /* { */
}

From reading his 1972 code it's clear Dennis was a fan of switch statements - he used them quite a bit. It's not so surprising given that almost everything was encoded as an int partly for lack of other data type possibilities. His compiler implementation used no structs at that stage because he was just in the middle of adding them to the language. Dynamic dispatch, vtables and polymorphism were a long way off. I've tried and failed to find a reference for this but if I recall correctly Dennis "invented" switch statements or at least contributed ideas leading to the form they take in C and considered them one of his best or proudest additions to the language.

The ability to leave out the braces makes switch statements formally similar to if, for, do and while statements, helping to simplify and unify the grammar. See the selection-statement and iteration-statement productions in the C grammar (e.g. in Appendix A13 of Kernighan and Ritchie, pages 236-237 in my copy) where these things are defined.

Obviously one can always add braces but maybe that seems heavy for such simple examples as this one. This example could be coded as a disjunctive if statement but I think one of the ideas Dennis had for switch was that the compiler is more clearly being offered the opportunity to optimise the implementation of the branching logic based on the particular constants involved.

滥情空心 2024-12-22 11:35:35

我想到了另一个案例。

假设我有一个 unsigned char 类型的计数器,指示循环的迭代次数,但如果计数器等于 0,则需要循环 256 次。如果我的想法是正确的,您可以按如下方式编码:

uint8_t counter;
/* counter will get its value here somewhere */
switch (counter)
    default:
        while (0 < counter)
        {
            case 0:
                /* Perform action */
                counter--;
        }

这当然假设从 0x00 下溢导致无符号字符为 0xFF。但它适用于我的所有环境,尽管 PC Lint 会抱怨......
是的,它包含大括号,但仅用于 while,而不是用于 switch。如果你知道更好的事情,请让我听听!

我会这样编程吗?绝不! ...好吧,在小型 8 位处理器上我什至可以! :-)

I've thought of another case.

Suppose I have a counter of type unsigned char indicating the number of iterations of a loop, but if the counter equals zero, it needs to go through the loop 256 times. If my thinking is correct, you could code this as follows:

uint8_t counter;
/* counter will get its value here somewhere */
switch (counter)
    default:
        while (0 < counter)
        {
            case 0:
                /* Perform action */
                counter--;
        }

This of course assumes that underflow from 0x00 results in 0xFF for an unsigned char. But it does for all my environments, even though PC Lint will complain...
And yes, it contains braces, but just for the while, not for the switch. If you know something better, let me hear it!

Would I program like this? Never! ... well, on a small 8-bit processor I even might! :-)

淤浪 2024-12-22 11:35:35

第 6.8.4.2 节 switch 语句说:

switch 语句使控制跳转到、进入或越过
语句是 switch 主体,取决于 a 的值
控制表达,以及默认标签的存在和
开关主体上或内部的任何 case 标签的值。案例或默认
标签只能在最近的封闭开关内访问
声明。

术语 switch-body最封闭的 switch-statement 似乎不需要大括号。
所以你是对的,这看起来很奇怪,但却是合法的。 (以前没见过)

Section 6.8.4.2 The switch statement says:

A switch statement causes control to jump to, into, or past the
statement that is the switch body, depending on the value of a
controlling expression, and on the presence of a default label and the
values of any case labels on or in the switch body. A case or default
label is accessible only within the closest enclosing switch
statement.

The terms switch-body and closest enclosing switch-statement seem not to require braces.
So you're right it looks weird but is legal. (Never saw that before)

°如果伤别离去 2024-12-22 11:35:35

在实践中,出于可读性的原因,开关与大括号一起使用(即使在达夫的设备中)。添加大括号也没有什么害处。

In practice switches are used with braces (even in Duff's device) for readability reasons. And adding braces does no harm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文