Changing a string macro at compile time

I am developing a unique client that needs to work on different machines. On each computer, the server runs on a different IP address, but this address is known.

I don't want to tell the client which IP is every time I start it, so I tell it at compile time.

The problem is when compiling with g++ -DHOSTNAME=127.0.0.1

(also with double quotes) the compiler says:

error: too many decimal points in number
./include/Client.h:18:25: note: in expansion of macro ‘HOSTNAME’

      

I tried it too using localhost.

error: ‘localhost’ was not declared in this scope
./include/Client.h:18:25: note: in expansion of macro ‘HOSTNAME’

      

Also tried using some things found on the internet.

#define XSTR(x) STR(x)
#define STR(x)

      

Compilation error:

./src/BSCClient.cpp:15:45: note: #pragma message: HOSTNAME: 
#pragma message("HOSTNAME: " XSTR(HOSTNAME))

./src/BSCClient.cpp:16:39: error: too few arguments to functionhostent* gethostbyname(const char*)server = gethostbyname(XSTR(HOSTNAME));

      

At this point, I think that maybe macros are not the best way to handle this, but I don't understand how.

If anyone has any links I would appreciate it.

EDIT: These are the codes.

client.h:

#ifndef __CLIENT_HH__
#define __CLIENT_HH__

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <string>
#include <iostream>

using namespace std;

#define HOSTNAME 127.0.0.1
#define MAX_MESSAGE_LENGTH 10 

class Client {
private:
    string client_name;
    int sockfd, portno;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    error(const char *msg);

public:

    BSCClient (string name, int port);
    void identifyme();
    void sendData (string data);
    string recvData ();

    void closeSocket();
};

#endif

      

client.cpp

#include "BSCClient.h"

#include <stdlib.h>
#include <time.h>

void BSCClient::error(const char *msg)
{
    perror(msg);
    exit(0);
}

Client::Client(string name, int port)
{
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    portno = port;
    client_name = name;

    if (sockfd < 0) 
        error("ERROR opening socket");

    server = gethostbyname(HOSTNAME);

    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
        error("ERROR connecting");

    sendData(client_name);
}

void Client::identifyme() {
    FILE *fp;
    fp = popen("id -gn", "r");

    char text[6];
    fscanf(fp, "%s", text);
    pclose(fp);
    string data(text);
    sendData(data);
}

void Client::sendData (string data) {
    const char *sdata = data.c_str();
    int n;
    n = write(sockfd, sdata, strlen(sdata));
    if (n < 0) 
         error("ERROR writing to socket");
}

string Client::recvData () {
        int n;
        int bytes;
        char *longitud = new char[MAX_MESSAGE_LENGTH+1];
        n = read(sockfd, longitud, MAX_MESSAGE_LENGTH);
        if (n < 0) {
                error("ERROR recieving size of output");
        }
        bytes=atoi(longitud);
        //Para forzar el fin del string (ya que al imprimir el string hay veces que muestra caracteres de más)
        longitud[MAX_MESSAGE_LENGTH]='\0';
        char *data = new char[bytes];
        n = read(sockfd, data, bytes);
        if (n < 0)
                error("ERROR reading output");
        string ret(data);
        return ret;
} 

void Client::closeSocket() {
    close(sockfd);
}

      

+3


source to share


2 answers


You need to avoid double quotes:

g++ -DHOSTNAME=\"127.0.0.1\"

      

Otherwise, the quotes just tell your shell what 127.0.0.1

is the value you want to supply -DHOSTNAME

, which can be useful if the value has spaces, for example:

g++ -DMAGIC_NUMBER="150 / 5"

      

(there, MAGIC_NUMBER

will be replaced with 150 / 5

no quotes)

If you want the quotes to be part of the macro (as in #define HOSTNAME "127.0.0.1"

), you have to tell your shell that they are part of the value you give -DHOSTNAME

, this is done by escaping.

EDIT



Also, as Angew pointed out, you misused the XSTR trick. This is a different solution to your problem than my answer.

It certainly works like this:

#define XSTR(x) STR(x)
#define STR(x) #x

      

With this, you don't need to hide the quotes.

These two macros change the text 127.0.0.1

to "127.0.0.1"

. The macro XSTR

allows HOSTNAME

expansion before 127.0.0.1

the macro STR

converts it to "127.0.0.1"

. If you used a macro directly STR

, you should have "HOSTNAME"

instead "127.0.0.1"

.

I think I prefer the escaping solution to use the trick involving two macros in the code, but that works too.

+5


source


It seems strange that you want to write it to an executable file. It should be more flexible to use something like getenv("MY_SERVER_ADDR")

and just set this environment variable before starting your server. Or, of course, you could do a more typical thing and think of it as a command line argument, but something tells me that you've already decided not to.



A somewhat strange idea, if you are on Linux, is to write the IP address to a text file and create an ELF object file using ld

and objcopy

; you can load this application as a generic object, or even static if you really want to "hard-code" it. But I'm not sure why this would be preferable to the previously mentioned options.

0


source







All Articles