【问题标题】:Is there a way to get rid of this switch and make it into a smaller block of code?有没有办法摆脱这个开关并把它变成一个更小的代码块?
【发布时间】:2021-04-29 09:25:55
【问题描述】:

我的代码中有这个开关,它占用了大量空间。有没有办法把它变成更小的代码块?

switch(datatype)
{
    case OSMP_BYTE: // char
    {
        datatypeSize = sizeof(char);
        break;
    }
    case OSMP_INT: // int
    {
        datatypeSize = sizeof(int);
        break;
    }
    case OSMP_SHORT: // short int
    {
        datatypeSize = sizeof(short int);
        break;
    }
    case OSMP_LONG: // long int
    {
        datatypeSize = sizeof(long int);
        break;
    }
    case OSMP_UNSIGNED_CHAR: // unsigned char
    {
        datatypeSize = sizeof(unsigned char);
        break;
    }
    case OSMP_UNSIGNED: // unsigned int
    {
        datatypeSize = sizeof(unsigned int);
        break;
    }
    case OSMP_UNSIGNED_LONG: // unsigned long int
    {
        datatypeSize = sizeof(unsigned long int);
        break;
    }
    case OSMP_FLOAT: // float
    {
        datatypeSize = sizeof(float);
        break;
    }
    case OSMP_DOUBLE: // double
    {
        datatypeSize = sizeof(double);
        break;
    }

    default:
        break;
}

我的数据类型是这样定义的:

typedef enum {
    OSMP_SHORT = 1,
    OSMP_INT,
    OSMP_LONG,
    OSMP_UNSIGNED_CHAR,
    OSMP_UNSIGNED,
    OSMP_UNSIGNED_LONG,
    OSMP_FLOAT,
    OSMP_DOUBLE,
    OSMP_BYTE
} OSMP_Datatype;

如果有办法让它更小,更适合我的代码,我真的会得到帮助。

【问题讨论】:

  • 当然,查找表。问题是你调用了多少次?最后真的很重要吗?您可以通过将其作为一个函数来最小化代码,而只需 return sizeof(...),避免所有 break 垃圾。然后你可以将每个定义写成一行。
  • 您可以将开关的每个case:写在一行以节省空间,例如case OSMP_BYTE: datatypeSize = sizeof(char); break; -- 由你决定。查找表是另一个不错的选择。
  • 你在设计什么系统?这些枚举代表什么?您是否对数据进行任何其他操作?
  • 你可以去掉花括号,你可以使用 X-macros 来压缩 case 子句:例如 CASE(UNSIGNED_CHAR, unsigned char); where #define CASE(E, T) case OSMP_##E: datatypeSize = sizeof(T); break -- 不过我同意第一条评论质疑紧凑和/或易于编辑的重要性。因为看起来您不太可能添加其他类型的负载或显着修改它们。通常,最不晦涩的代码是最好的代码。但是稍微整理一下,因为你的太冗长了。
  • 我正在设计一个使用共享内存传递操作系统消息的库

标签: c switch-statement


【解决方案1】:

这是 cmets 中建议的一种可能的查找表方法:

typedef enum {
    OSMP_SHORT = 0,
    OSMP_INT,
    OSMP_LONG,
    OSMP_UNSIGNED_CHAR,
    OSMP_UNSIGNED,
    OSMP_UNSIGNED_LONG,
    OSMP_FLOAT,
    OSMP_DOUBLE,
    OSMP_BYTE,
} OSMP_Datatype;

size_t OSMP_Size[] = 
{
    [OSMP_SHORT] = sizeof(short int),
    [OSMP_INT] = sizeof(int),
    [OSMP_LONG] = sizeof(long int),
    [OSMP_UNSIGNED_CHAR] = sizeof(unsigned char),
    [OSMP_UNSIGNED] =  sizeof(unsigned int),
    [OSMP_UNSIGNED_LONG] = sizeof(unsigned long int),
    [OSMP_FLOAT] = sizeof(float),
    [OSMP_DOUBLE] = sizeof(double),
    [OSMP_BYTE] = sizeof(char),
};

size_t sizeofType(OSMP_Datatype type)
{
    if((type >= 0) && (type < sizeof(OSMP_Size)/sizeof(size_t)))
        return OSMP_Size[type];
    else
        return 0;
}

这里最好枚举是连续的并且从零开始,因为它使查找更容易实现。请注意,这使用指定的初始化程序,因此它仅适用于 C99 及更高版本。正如@paddy 所指出的,也与 C++ 不兼容。

此外,代码可能看起来更紧凑,但不要期望它的性能比您的 switch-case 更好。

【讨论】:

  • 不知道sizeofType(OSMP_LONG)会返回什么...
  • 糟糕!我在复制粘贴时错过了那个,但要回答你的问题,它会返回 0。
  • 嗯,我知道它会返回什么......关键是这种类型的代码很容易出错。作为一个“小”改进,我建议初始化器的放置顺序与枚举相同
  • 很好的定位。指定的数组初始值设定项在 C 中很方便,但应该提到它们不能移植到 C++(这有时是可取的)。如果sizeofType 即将在任一代码路径中返回零,则断言也可能有一些好处。
  • @4386427 比错过case OSMP_LONG 更容易吗?还是一长串开关案例中的一个中断?是的,当然,更改顺序是有意义的,谢谢!
【解决方案2】:

我的数据类型是这样定义的:

为了好玩,试试:

typedef enum {
    OSMP_SHORT = (0 << 16) | sizeof(short),
    OSMP_INT = (1 << 16) | sizeof(int),
    OSMP_LONG = (2 << 16) | sizeof(long),
    OSMP_UNSIGNED_CHAR = (3 << 16) | sizeof(unsigned char),
    OSMP_UNSIGNED = (4 << 16) | sizeof(unsigned),
    OSMP_UNSIGNED_LONG = (5 << 16) | sizeof(unsigned long),
    OSMP_FLOAT = (6 << 16) | sizeof(float),
    OSMP_DOUBLE = (7 << 16) | sizeof(double),
    OSMP_BYTE = (8 << 16) | sizeof(uint8_t),
} OSMP_Datatype;

#define OSMP_DataSizeMask 0x0000FFFF

..然后代码可以是:

    datatypeSize = datatype & OSMP_DataSizeMask;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-15
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-22
    相关资源
    最近更新 更多