googytech
googytech

Reputation: 479

Error in Macro Definition - does not give a valid preprocessing token

Have a very simple cpp code.

FileName: 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);
}

FileName: 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

Getting the following compilaton error:

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'

The logic with json_string is filled for dummy purpose in the above example.

How do we access the member variable of a structure by keeping in reference another descriptor structure, containing the member variable name stored.

Thanks in advance.

Upvotes: 0

Views: 225

Answers (1)

Indiana Kernick
Indiana Kernick

Reputation: 5341

After a long chat, I've figured out what you're trying to do and was able to rewrite it in modern C++. This is what I came up with:

#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;
}

The output of this program is:

message_id|1234
message|data

Having Message_Descriptor_t refer back to Message_t doesn't really seem necessary to me. The only benefit it seems to add is order. The code can be simplified further, leaving almost no resemblance to the original code.

#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;
}

Compare this with the original C-like C++ code in the question and you'll see why I love C++ so much.

Upvotes: 1

Related Questions