【问题标题】:use c Token-Pasting to access field in struct使用 c Token-Pasting 访问结构中的字段
【发布时间】:2013-11-18 19:28:23
【问题描述】:

我正在尝试使用 c 令牌粘贴 (##) 来访问结构字段,如下所示:

typedef struct
{
   int a;
   int b;
} TMP_T;

#define BUILD_FIELD(field) my_struct.##field

int main()
{
     TMP_T my_struct;
     BUILD_FIELD(a) = 5;
     return 0;
}

但在编译过程中出现以下错误: 错误:粘贴“。”并且“a”没有给出有效的预处理令牌

我想为此添加额外的案例:

 typedef struct {
 int a;
 int b;
 }TMP_T;

 #define BUILD_FIELD(my_struct,field) my_struct.##field


  void func(char* name)
  {
TMP_T tmp_str;
if((name == "a")  || (name == "b"))
{
    BUILD_FIELD(tmp_str, name) = 7;
    printf("%d \n", BUILD_FIELD(a) );
}


 }

 int main()
 {

       func("a");
       return 1;
 }

我应该如何使用宏来访问特定的结构和字段。是否可以?或者因为它是预编译的,所以无法为各种字段(a,b)定义它

谢谢 莫提

【问题讨论】:

  • 这是完全错误的。您不能将宏与运行时的东西混合使用。宏处理在预处理之后结束,甚至在编译之前。也许您需要一种脚本语言。最后,您不能将字符串与== 进行比较。
  • 在下面我的回答中解决您的最后一次编辑。同意@perreal 的两个观察。

标签: c struct


【解决方案1】:

您根本不需要粘贴令牌:

#define BUILD_FIELD(field) my_struct.field

根据gcc manual 标记粘贴应该在连接后产生一个标识符或一个数字。错误是由于.a 也不是。

【讨论】:

  • 感谢您让我在## 上受到限制。我以前从未使用过它,但现在很可能会。
  • 谢谢,其实我没有问正确的问题。我将该字段作为指向函数的指针,如下所示: typedef struct { int a;诠释 b; }TMP_T; #define BUILD_FIELD(my_struct,field) my_struct.##field void func(char* name) { TMP_T tmp_str; if((name == "a") || (name == "b")) { BUILD_FIELD(tmp_str, name) = 7; printf("%d \n", BUILD_FIELD(a) ); } } int main() { func("a");返回 1; }
  • 我现在很好奇。我运行了我的代码,就像我的答案中显示的那样,除了##,就像 OP 一样。它导致没有错误。根据我在 link here 中读到的内容,它不应该有。那么,您能否详细说明您所说的导致 OP 错误的原因? (错误是由于 .a 也不是。
  • @ryyker,看看答案中的链接,它解释得很清楚。粘贴后,gcc 期望有一个标识符或一个数字。您正在使用 MS 编译器进行编译,因此它的行为可能会有所不同。在任何情况下,都不需要粘贴。
  • @moti - 您能否将所有这些内容放入您的原始帖子中,并使用一些格式以便更容易阅读,并且可以更清楚地解决问题?
【解决方案2】:

只需使用宏替换字符串field。试试这个:

#define BUILD_FIELD(field) my_struct.field

所以下面的代码可以工作:

#include <ansi_c.h>

typedef struct  {
    int a;
    int b;
}TMP_T;

#define BUILD_FIELD(field) my_struct.field

int main(void)
{
     TMP_T my_struct;
     BUILD_FIELD(a) = 5;
     printf("my_struct.a is %d\n",my_struct.a); 
     BUILD_FIELD(b) = 10;
     printf("my_struct.b is %d\n",my_struct.b); 
     return 0;
}  

顺便说一下,我也运行了上面的代码:(读完 Krister Andersson's link强>)

#define BUILD_FIELD(field) my_struct.##field    

它在没有使用## 字符串化的情况下运行与代码相同。因此,我们的编译器之间显然存在一些不同。
无论如何,我希望我最初的断言不会造成太多混乱。你的问题让我今天学到了一些教训。谢谢! (+1)

解决您最新的帖子编辑:

首先,此修改将导致此处 TMP_T 中的未知字段名出现编译错误:

BUILD_FIELD(tmp_str, name) = 7;   

这是一个 good link,讨论了预处理、编译和链接(本次讨论最感兴趣的是预处理和编译部分)。除其他事项外,它还讨论了何时使用宏。

另外,关于这条线:

if((name == "a")  || (name == "b"))  

进行字符串比较时,不使用==strcmp(),甚至strstr()都用于字符串比较。

【讨论】:

  • 投反对票。至少说明你为什么不投票。如果有问题我会解决的。
  • ## 在 C 中非常合法。gcc.gnu.org/onlinedocs/cpp/Concatenation.html
  • @perreal - 我的立场是正确的。 (并学到了一些我不知道的东西)我会修改我的帖子。谢谢。
  • @KristerAndersson - 我真的不知道。修改了我的帖子。谢谢你的链接:)
【解决方案3】:

如果您使用某些“结构”创建结构,则需要粘贴。例如:

 typedef struct
 {
    int tmp_a;
    int tmp_b;
 } TMP_T;

 #define BUILD_FIELD(field) my_struct.tmp_##field

它用于标记化。您的用例是“典型的”宏变量替换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    • 2010-11-03
    • 2020-12-26
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多