用于计算(字符)参数的宏

发布于 2024-11-28 12:43:31 字数 638 浏览 1 评论 0原文

我有一个宏将字符串转换为字符列表:

#define TO_STRING(x) #x
#define CHAR_LIST_7(x)   TO_STRING(x)[0] \
                       , TO_STRING(x)[1] \
                       , TO_STRING(x)[2] \
                       , TO_STRING(x)[3] \
                       , TO_STRING(x)[4] \
                       , TO_STRING(x)[5] \
                       , TO_STRING(x)[6]

例如用法: “CHAR_LIST_7(chicken)”给出“'c', 'h', 'i', 'c', 'k', 'e', 'n'”,因此它可以用于模板之类的东西(例如:http://hpaste.org/47313/exand

但是,我想概括一下这对于任意数量的字符(并且不需要手动计算字符数量)?所以我可以简单地去:CHAR_LIST(任意文本)。有什么想法或解决方案吗?

I have a macro to convert a string to a list of characters:

#define TO_STRING(x) #x
#define CHAR_LIST_7(x)   TO_STRING(x)[0] \
                       , TO_STRING(x)[1] \
                       , TO_STRING(x)[2] \
                       , TO_STRING(x)[3] \
                       , TO_STRING(x)[4] \
                       , TO_STRING(x)[5] \
                       , TO_STRING(x)[6]

e.g. usage:
"CHAR_LIST_7(chicken)" gives "'c', 'h', 'i', 'c', 'k', 'e', 'n'" so it can be used in things like templates (e.g.: http://hpaste.org/47313/exand )

However, I would like to generalize this for any amount of characters (and not need to manually have to count the amount of characters)? So I could simply go: CHAR_LIST(arbitrary text). Any ideas or solutions ?

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

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

发布评论

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

评论(3

铁轨上的流浪者 2024-12-05 12:43:31

您无法在预处理期间拆分标记,只能将它们组合起来(使用 ##)。

将标识符转换为字符串文字不会有任何帮助,因为您无法在预处理期间将字符串文字分开,也无法对字符串文字执行操作(例如计算长度)。

在预处理期间,编译器知道标记是字符串文字以及它是什么类型的文字,但它还不知道其完整类型和长度,至少不知道宏可以访问的方式。

You can't split tokens during preprocessing, you can only combine them (using ##).

Converting the identifier to a string literal won't help either as you can't string split a string literal apart during preprocessing, nor can you perform operations (e.g. compute length) on a string literal.

During preprocessing the compiler knows that a token is a string literal and what kind of literal it is, but it does not yet know its full type and length, at least not in a way that is accessible to a macro.

橘虞初梦 2024-12-05 12:43:31

不,正如詹姆斯已经说过的,没有办法在预处理器中分割标记或让它知道字符串的长度。

但我认为对于您的用例来说,无论如何这都是没有必要的。使用 #x 对参数进行字符串化所得到的字符串是一个恒定大小的字符串,例如 chicken 导致 "chicken" ,它只是输入char[8]。这样的字符串的长度是一个编译时常量,您只需使用 sizeof 即可检测到它:

#define TOKLEN(TOK) (sizeof(#TOK)-1)

在 C 中使用这样的东西看起来“简单”

#define SCARY(TOK) for (size_t i = 0; i < TOKLEN(TOK); ++i) printf("%c:", #TOK[i])

,因为 TOKLEN(TOK) > 是一个编译时常量,编译器可以在适当的情况下展开它。

要在 C++ 用例中使用它

template < size_t n >
class constLenString {
  size_t const len = n;
  char const* str;
  constLenString(char* s) : str(s) { }
};

#define defConstLenString(TOK, NAME) constLenString< TOKLEN(TOK) > NAME(#TOK)

(未经测试,我的 C++ 很生疏)

,现在使用

defConstLenString(chicken, chick);

chick.n 是一个常量,可以是 for 循环的边界或不管怎样,编译器应该能够完美地优化一切。

No, as James already said, there is no way to split tokens in the preprocessor or to have it to know the length of a string.

But I think that for your use case this is not necessary at all in any case. A string that you would get from stringifying your argument with #x is a constant sized string, e.g chicken leads to "chicken" which simply has type char[8]. The length of such a string is a compile time constant and you simply can detect it with sizeof:

#define TOKLEN(TOK) (sizeof(#TOK)-1)

Usage of such a thing in C would "simply" look

#define SCARY(TOK) for (size_t i = 0; i < TOKLEN(TOK); ++i) printf("%c:", #TOK[i])

Because TOKLEN(TOK) is a compile time constant the compiler could unroll this if appropriate.

To use that in your use case for C++

template < size_t n >
class constLenString {
  size_t const len = n;
  char const* str;
  constLenString(char* s) : str(s) { }
};

#define defConstLenString(TOK, NAME) constLenString< TOKLEN(TOK) > NAME(#TOK)

(untested, my C++ is rusty)

and now with

defConstLenString(chicken, chick);

chick.n is a constant that can be the bound of a for loop or whatever and the compiler should be able to optimize everything perfectly.

魂牵梦绕锁你心扉 2024-12-05 12:43:31

您要求拆分的方式在一般形式中是不可能的。最好的方法是向模板提供参数:

Literal<'c','h','i','c','k','e','n'>::print();

我知道这会需要更多的输入。为了克服这个问题,您可以编写一个简单的程序,它将像 chicken 这样的字符串文字作为参数,并将其输出到 'c','h','i',...等。类似于:

int main(int argc, char **argv)
{
  if(argc != 2)
    return 0;
  const char *s = argv[1];
  int length = strlen(s)-1;
  for(int i = 0; i < length; i++)
    cout<<s[i]<<",";
  cout<<s[length]<<endl;
}

但是,由于 template 参数中存在分割字符,因此无法解决冗长的问题。

The way you ask for splitting is not possible in general form. The best way is to provide the argument as it's to the template:

Literal<'c','h','i','c','k','e','n'>::print();

I know that it will be a bit more of typing. To overcome that you can write a simple program, which takes a string literal like chicken as argument and outputs it into 'c','h','i',...etc. something like:

int main(int argc, char **argv)
{
  if(argc != 2)
    return 0;
  const char *s = argv[1];
  int length = strlen(s)-1;
  for(int i = 0; i < length; i++)
    cout<<s[i]<<",";
  cout<<s[length]<<endl;
}

However, there is no solution for verbosity due to split-ted characters in your template argument.

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