寻找一个宏添加两个字符在一起的开关情况

Looking for a MACRO adding two characters together for switch cases

本文关键字:在一起 字符 开关 两个 情况 添加 一个 寻找      更新时间:2023-10-16

我在一个旧的网络引擎上工作,通过网络发送的包类型由2字节组成。

这或多或少是人类可读的形式,例如"LO"代表Login。

在读取数据的部分有一个巨大的开关,像这样:

short sh=(((int)ad.cData[p])<<8)+((int)ad.cData[p+1]);
switch(sh)
{
    case CMD('M','D'):
    ..some code here
    break

其中CMD为定义:

#define CMD(a,b) ((a<<8)+b)

我知道有更好的方法,但只是为了清理一点,也能够更容易地搜索标签(说"LO")(而不是搜索不同类型的"'L','O'"或"'L','O'"或偶尔的"'L','O'"<-空格使其难以搜索)我试图为开关做一个宏,所以我可以使用"LO"代替定义,但我只是不能让它编译。

所以这里有一个问题:如何将#define更改为我可以像这样使用的宏:

case CMD("MD"):
..some code here
break

它开始作为一个小的子任务,使生活更容易一点,但现在我不能把它从我的头,谢谢任何帮助!

干杯!

[编辑]代码工作,它的世界是错的!ie。Visual Studio 2010在这方面有一个bug。

基于宏的解决方案

字符串字面值实际上是char const[N]的一个实例,其中N是字符串的长度,包括结束的空字节。考虑到这一点,您可以通过使用string-literal[idx]指定您想要读取存储在偏移量idx的字符来轻松访问字符串文字中的任何字符。

#define CMD(str) ((str[0]<<8)+str[1])

<一口>

CMD("LO") => (("LO"[0]<<8)+"LO"[1]) => (('L'<<8)+'0')

你应该记住,没有什么可以阻止你使用上面的宏与长度小于2的字符串,这意味着你可能会遇到未定义的行为如果你试图读取一个实际上无效的偏移量。


推荐: c++ 11,使用constexpr函数

您可以创建一个可以在常量表达式中使用的函数(并且在case-labels中使用),使用引用const char[3]的形参,这是您的string-literal " foo ""real"类型。

constexpr short cmd (char const(&ref)[3]) {
  return (ref[0]<<8) + ref[1];
}
int main () {
  short data = ...;
  switch (data) {
    case cmd("LO"):
      ...
  }
}

c++ 11和用户定义的字面值

在c++ 11中,我们被赋予了定义用户定义字面值的可能性。这将使您的代码更容易维护和解释,并且使用起来更安全:

#include <stdexcept>
constexpr short operator"" _cmd (char const * s, unsigned long len) {
  return len != 2 ? throw std::invalid_argument ("") : ((s[0]<<8)+s[1]);
}
int main () {
  short data = ...;
  switch (data) {
   case "LO"_cmd:
     ...
  }
}

case-label相关联的值必须通过常量表达式生成。上面的代码看起来可能会在运行时抛出异常,但由于case-label是常量表达式,编译器必须能够在翻译过程中计算"LO"_cmd

如果这是不可能的,如在"FOO"_cmd中,编译器将发出一个诊断,指出代码是病态的。