2014-10-06 3 views
3

Я разрабатываю уникальный клиент, который должен работать на разных машинах. На каждом компьютере сервер работает на другом 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)); 

На данный момент я думаю, что, возможно, макросы не правильный способ справиться с этим, но я не понять, как это сделать.

Если у кого-то есть какие-либо сведения об этом, я буду благодарен.

EDIT: Это коды.

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

+0

@Niall Нет, он говорит то же самое. Извините, я забыл написать, что я уже пробовал это. –

+1

@BorjaArias, Ok, также может быть полезно разместить фактический код, создающий ошибку, в дополнение к содержанию ошибки, которую вы уже опубликовали. – Niall

ответ

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"), вы должны сказать своей оболочке, что они являются частью значения, которое вы даете -DHOSTNAME, это делается путем их ускорения.

EDIT:

Кроме того, как отметил Angew, вы злоупотребили XSTR трюк. Это другое решение вашей проблемы, чем мой ответ.

Это, конечно, как это работает:

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

С, что вы не должны бежать кавычки.

Эти два макроса меняют текст 127.0.0.1 на "127.0.0.1". Макрос XSTR позволяет HOSTNAME быть расширенным до 127.0.0.1 перед макросом STR преобразует его в "127.0.0.1". Если вы использовали непосредственно макрос STR, в конечном итоге вы получите "HOSTNAME" вместо "127.0.0.1".

Я думаю, что я предпочитаю экранирующее решение использовать трюк с участием двух макросов в коде, но это тоже работает.

+0

спасибо, что работает. Сегодня я забыл добавить #x. Но на прошлой неделе я уверен, что написал это. В любом случае, теперь он работает. –

+0

Экранирование двойных кавычек не работает. Компилятор печатает ту же ошибку, что и без ее выхода. –

+0

Вы избежали их точно так же, как в моем первом примере? Кроме того, вы удалили '#define HOSTNAME 127.0.0.1' в свой код? (если вы этого не сделали, вы должны увидеть предупреждение о переопределении HOSTNAME) – Dettorer

0

Это кажется странным, что вы хотите жестко закодировать это в исполняемый файл. Должно быть более гибким использовать что-то вроде getenv("MY_SERVER_ADDR") и просто установить эту переменную среды перед запуском вашего сервера. Или, конечно, вы могли бы сделать более типичную вещь и считать ее аргументом командной строки, но что-то говорит мне, что вы уже решили не делать этого.

Немного странная идея, если вы находитесь в Linux, - это записать IP-адрес в текстовый файл и создать объектный файл ELF с помощью ld и objcopy; вы можете загрузить это приложение в качестве общего объекта или даже статического, если вы действительно хотите «жестко закодировать» его. Но я не уверен, почему это было бы предпочтительнее ранее упомянутых опций.

+0

Я работаю в многопользовательской системе, поэтому по соображениям безопасности я предпочитаю избегать использования переменной окружения. –

+0

Как насчет файла конфигурации (это может быть однострочный файл с именем хоста внутри), на который пользователи не могли писать? – Ale

Смежные вопросы