Reputation: 115
I'm developing an unique client that has to work on different machines. In every machine the server is running in a different IP address, but this address is known.
I don't want to tell the client which is the IP every time I run it, so I though about tell it in compilation time.
The problem is that when compiling with g++ -DHOSTNAME=127.0.0.1
(also tried with double quotes) the compiler is saying:
error: too many decimal points in number
./include/Client.h:18:25: note: in expansion of macro ‘HOSTNAME’
I tried it using localhost, too.
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)
compile 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 function ‘hostent* gethostbyname(const char*)’
server = gethostbyname(XSTR(HOSTNAME));
At this point I'm thinking that maybe macros isn't the proper way to handle this, but I don't figure out how to do it.
If someone has any reference about it I will be thankful.
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);
}
Upvotes: 4
Views: 4105
Reputation: 1336
You have to escape the double quotes:
g++ -DHOSTNAME=\"127.0.0.1\"
Otherwise, the quotes are just saying to your shell that 127.0.0.1
is the value you want to give to -DHOSTNAME
, which can be useful if the value has whitespaces for example:
g++ -DMAGIC_NUMBER="150 / 5"
(there, MAGIC_NUMBER
will be replaced by 150 / 5
without the quotes)
If you want the quotes to be part of the macro (as in #define HOSTNAME "127.0.0.1"
), you have to say to your shell that they are part of the value you give to -DHOSTNAME
, this is done by escaping them.
EDIT:
Also, as pointed out by Angew, you misused the XSTR trick. It is an other solution to your problem than my answer.
It certainly works like this:
#define XSTR(x) STR(x)
#define STR(x) #x
With that you don't have to escape the quotes.
These two macros change the text 127.0.0.1
into "127.0.0.1"
. The XSTR
macro allows HOSTNAME
to be expanded to 127.0.0.1
before the STR
macro converts it to "127.0.0.1"
. If you used directly the STR
macro, you would end up with "HOSTNAME"
instead of "127.0.0.1"
.
I think I prefer the escaping solution to the use of a trick involving two macros in the code, but that works too.
Upvotes: 9
Reputation: 249093
It seems odd that you'd want to hard-code this into the executable. It should be more flexible to use something like getenv("MY_SERVER_ADDR")
and just set that environment variable before running your server. Or of course you could do the more typical thing and take it as a command line argument, but something tells me you already decided not to do that.
A slightly weirder idea if you are on Linux is to write the IP address into a text file and create an ELF object file from that using ld
and objcopy
; you can then load this into your app as a shared object or even a static one if you really want to "hard code" it. But I'm not sure why this would be preferable to the previously mentioned options.
Upvotes: 0