c++ - 宏定义错误 - 未提供有效的预处理标记

标签 c++ macros c-preprocessor

有一个非常简单的cpp代码。

文件名:file.cpp

#include "file.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

using namespace std;
int main()
{
  Message_t msg;
  memset(&msg,0,sizeof(Message_t));

  msg.message_id = 1234;
  strcpy(msg.message,"data");

  Message_Descriptor_t desc ;
  memset(&desc, 0, sizeof(Message_Descriptor_t));
  desc.no_of_fields = 2;
  desc.fields = malloc(2 * sizeof(Field_Descriptor_t));

  strcpy(desc.fields[0].var_name, "message_id");
  desc.fields[0].type = FIELD_INT;
  strcpy(desc.fields[1].var_name, "message");
  desc.fields[1].type = FIELD_CHAR;
  char *json_string = "";
  BUILD_MSG(msg,desc,json_string);
}

文件名:file.hpp

#ifndef _FILE_HPP_
#define _FILE_HPP_

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

typedef struct Message_s
{
  int message_id;
  char *message;
} Message_t;


typedef enum
{
  FIELD_INT = 0,
  FIELD_CHAR = 1
} FieldType_e;


typedef struct Field_Descriptor_s
{
  char *var_name;
  FieldType_e type;
} Field_Descriptor_t;

typedef struct Message_Descriptor_s
{
  int no_of_fields;
  Field_Descriptor_t *fields;
} Message_Descriptor_t;

#define BUILD_STRING(key, value ,json_string) \
{ \
   strcat(json_string, key);  \
   strcat(json_string, "|"); \
   strcat(json_string, value. ## key); \
}

#define BUILD_INT(key, value ,json_string) \
{ \
   strcat(json_string, key);  \
   strcat(json_string, "|"); \
   char buffer [33]; \
   strcat(json_string, key); \
}
#define BUILD_MSG(msg, msg_descriptor, json_string) \
{ \
  for (int i=0; i < msg_descriptor.no_of_fields; i++) \
  { \
    Field_Descriptor_t field = msg_descriptor.fields[i]; \
    char *var_name = NULL; \
    strcpy(var_name, field.var_name); \
    switch(field.type) \
    { \
      case FIELD_CHAR: \
        BUILD_STRING(var_name, msg, json_string); \
        break; \
      case FIELD_INT: \
        BUILD_INT(var_name, msg, json_string); \
        break; \
      default: \
        break; \
    } \
  } \
}

#define BUILD_JSON_MSG (msg, msg_descriptor, json_string) \
{ \
  BUILD_MSG(msg,msg_descriptor); \
}

#endif

出现以下编译错误:

g++ -c file.cpp
In file included from file.cpp:1:
file.cpp:25:1: error: pasting "." and "var_name" does not give a valid preprocessing token
file.cpp: In function 'int main()':
file.cpp:18: error: invalid conversion from 'void*' to 'Field_Descriptor_t*'
file.cpp:25: error: 'struct Message_t' has no member named 'var_name'

在上面的例子中,json_string 的逻辑是为了虚拟目的而填充的。

我们如何通过引用另一个包含存储的成员变量名称的描述符结构来访问结构的成员变量。

提前致谢。

最佳答案

经过长时间的交谈,我弄清楚了您想要做什么,并且能够用现代 C++ 重写它。这是我想出的:

#include <string>
#include <vector>
#include <variant>
#include <iostream>
#include <unordered_map>

using Field_t = std::variant<int, std::string>;
using Message_t = std::unordered_map<std::string, Field_t>;
using Field_Descriptor_t = std::string;
using Message_Descriptor_t = std::vector<Field_Descriptor_t>;

struct Visitor {
  std::string &json_string;

  void operator()(const int value) {
    json_string += std::to_string(value);
  }
  void operator()(const std::string &value) {
    json_string += value;
  }
};

void buildMsg(const Message_t &msg, const Message_Descriptor_t &desc, std::string &json_string) {
  Visitor visitor{json_string};
  for (const Field_Descriptor_t &field : desc) {
    json_string += field;
    json_string += '|';
    std::visit(visitor, msg.at(field));
    json_string += '\n';
  }
}

int main() {
  Message_t msg;
  msg["message_id"] = 1234;
  msg["message"] = "data";

  Message_Descriptor_t desc;
  desc.push_back("message_id");
  desc.push_back("message");

  std::string json_string;
  buildMsg(msg, desc, json_string);
  std::cout << json_string;
}

这个程序的输出是:

message_id|1234
message|data

Message_Descriptor_t 引用回 Message_t 对我来说似乎没有必要。它似乎增加的唯一好处是秩序。代码可以进一步简化,与原始代码几乎没有任何相似之处。

#include <string>
#include <vector>
#include <variant>
#include <iostream>

using Key = std::string;
using Value = std::variant<int, std::string>;
using Pair = std::pair<Key, Value>;
using Message = std::vector<Pair>;

struct Stringify {
  std::string &output;

  void operator()(const int value) {
    output += std::to_string(value);
  }
  void operator()(const std::string &value) {
    output += value;
  }
};

void stringifyMessage(std::string &output, const Message &message) {
  for (const Pair &pair : message) {
    output += pair.first;
    output += '|';
    std::visit(Stringify{output}, pair.second);
    output += '\n';
  }
}

int main() {
  Message message;
  message.emplace_back("message_id", 1234);
  message.emplace_back("message", "data");

  std::string output;
  stringifyMessage(output, message);
  std::cout << output;
}

将其与问题中原始的类似 C 的 C++ 代码进行比较,您就会明白为什么我如此喜欢 C++。

关于c++ - 宏定义错误 - 未提供有效的预处理标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58927023/

相关文章:

ios - 如何将对象放置在#define语句中

c - 了解 C 语言中的宏和预处理器指令

c++ - cpp unordered_set 只使用比较器而不是散列

c++ - R data.table和STRING_ELT()错误:如何修复 'character vector' vs 'char'错误?

c++ - 如何通过 GDAL 从位于 RAM 中的 geotiff 创建数据集

c++ - 有没有办法#if Objective-C++?

c - 允许使用什么类型的内容作为 C 预处理器宏的参数?

c++ - 为什么这段代码在第31行显示cout << x1 << x2;

rust - 发送要构造的宏的枚举变量

c++ - C++ 中预处理器方法的别名