2014-10-06 144 views
3

我正在开发一个必须在不同机器上工作的独特客户端。在每台机器上,服务器都运行在不同的IP地址上,但这个地址是已知的。在编译时更改字符串宏

我不想每次运行IP时都告诉客户端IP,因此我尽量在编译时告诉它。

的问题是,与g++ -DHOSTNAME=127.0.0.1编译时(也试图与双引号),编译时说:

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

我尝试了使用本地主机了。

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

也尝试使用在互联网上找到的一些东西。

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

编译错误:

./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)); 

在这一点上,我想,也许宏是不是来处理这个正确的方式,但我不知道如何做到这一点。

如果有人有任何参考,我会感激。编号: 这些是代码。

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); 
} 
+1

Client.h上的实际代码是什么:18? – Ale 2014-10-06 09:17:51

+0

@Niall不,它说的是一样的。对不起,我忘了写我已经尝试过。 – 2014-10-06 09:18:34

+1

@BorjaArias,好的,除了已经发布的错误内容之外,发布产生错误的实际代码也会很有用。 – Niall 2014-10-06 09:19:38

回答

5

你必须转义双引号:

g++ -DHOSTNAME=\"127.0.0.1\" 

否则,该报价只是说给你外壳127.0.0.1是你想给-DHOSTNAME的价值,它可以是如果该值有效具有例如空格:

g++ -DMAGIC_NUMBER="150/5" 

(那里,MAGIC_NUMBER将由150/5替换没有引号)

如果您希望引号是宏的一部分(如#define HOSTNAME "127.0.0.1"),您必须对您的shell说他们是您给-DHOSTNAME的值的一部分,这是通过转义它们来完成的。

编辑

此外,由Angew指出的那样,你滥用了XSTR伎俩。这是您的问题的另一种解决方案,而不是我的答案。

这当然是这样工作的:

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

随着你没有逃跑的报价。

这两个宏将文本127.0.0.1更改为"127.0.0.1"。在STR宏将其转换为"127.0.0.1"之前,XSTR宏允许将HOSTNAME扩展为127.0.0.1。如果您直接使用宏STR,则最终将以"HOSTNAME"而不是"127.0.0.1"结束。

我认为我更喜欢在代码中使用涉及两个宏的技巧的转义解决方案,但它也起作用。

+0

谢谢,这是有效的。今天我忘了添加#x。但是过去一周我确信我写了它。无论如何,现在它工作。 – 2014-10-06 09:50:52

+0

转义双引号不起作用。编译器打印相同的错误,因为没有转义它。 – 2014-10-06 09:59:45

+0

你是否像我的第一个例子那样逃脱了他们?另外,你是否删除了代码中的#define HOSTNAME 127.0.0.1? (如果你没有,你应该看到一个关于HOSTNAME被重新定义的警告) – Dettorer 2014-10-06 11:02:41

0

这似乎很奇怪,你会想硬编码到可执行文件。在使用类似getenv("MY_SERVER_ADDR")之类的应用程序时应该更加灵活,并且在运行服务器之前设置该环境变量。或者当然你可以做更典型的事情,并将其作为命令行参数,但有些事情告诉我你已经决定不这么做。

如果您使用的是Linux系统,您可以将IP地址写入文本文件并使用ldobjcopy创建一个ELF对象文件;那么你可以将它作为共享对象加载到你的应用中,或者如果你真的想要“硬编码”它,它甚至可以是静态的。但我不确定为什么这比以前提到的选项更可取。

+0

我正在使用多用户系统,所以出于安全原因,我宁愿避免使用环境变量。 – 2014-10-06 09:28:19

+0

用户无法写入的配置文件(可以是包含主机名的单行文件)如何? – Ale 2014-10-06 10:39:38