C++ 在编译时更改字符串宏
我正在开发一个独特的客户端,它必须在不同的机器上工作。在每台机器上,服务器都运行在不同的IP地址中,但该地址是已知的 我不想每次运行时都告诉客户端哪个是IP,所以我想在编译时告诉它 问题在于,当使用C++ 在编译时更改字符串宏,c++,string,c++11,macros,compilation,C++,String,C++11,Macros,Compilation,我正在开发一个独特的客户端,它必须在不同的机器上工作。在每台机器上,服务器都运行在不同的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’
g++-DHOSTNAME=127.0.0.1
进行编译时(也尝试使用双引号),编译器会说:
error: too many decimal points in number
./include/Client.h:18:25: note: in expansion of macro ‘HOSTNAME’
我也尝试过使用localhost
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));
在这一点上,我想也许宏不是处理这个问题的正确方法,但我不知道如何去做
如果有人对此有任何建议,我将不胜感激
编辑:
这些是代码
客户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
\ifndef\uuuu客户机\uhh__
#定义客户机__
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
#定义主机名127.0.0.1
#定义最大消息长度10
类客户端{
私人:
字符串客户端名称;
int sockfd,端口号;
服务地址中的结构sockaddr\u;
结构主机*服务器;
错误(常量字符*消息);
公众:
BSCClient(字符串名称,int端口);
void identifime();
void sendData(字符串数据);
字符串recvData();
void closeSocket();
};
#恩迪夫
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);
}
#包括“BSCClient.h”
#包括
#包括
void BSCClient::错误(const char*msg)
{
佩罗尔(味精);
出口(0);
}
客户端::客户端(字符串名称,int端口)
{
sockfd=套接字(AF_INET,SOCK_STREAM,0);
端口号=端口号;
客户名称=名称;
if(sockfd<0)
错误(“打开套接字时出错”);
服务器=gethostbyname(主机名);
如果(服务器==NULL){
fprintf(stderr,“错误,没有这样的主机\n”);
出口(0);
}
bzero((char*)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
b复制((字符*)服务器->h_地址,
(char*)和serv_addr.sin_addr.s_addr,
服务器->h_长度);
serv_addr.sin_port=htons(端口号);
if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
错误(“连接错误”);
sendData(客户名称);
}
void客户端::identifyme(){
文件*fp;
fp=popen(“id-gn”,“r”);
字符文本[6];
fscanf(fp,“%s”,文本);
pclose(fp);
字符串数据(文本);
发送数据(数据);
}
无效客户端::发送数据(字符串数据){
const char*sdata=data.c_str();
int n;
n=写入(sockfd、sdata、strlen(sdata));
if(n<0)
错误(“写入套接字时出错”);
}
字符串客户端::recvData(){
int n;
整数字节;
char*longitud=新字符[最大消息长度+1];
n=读取(sockfd、longitud、最大消息长度);
if(n<0){
错误(“接收输出大小错误”);
}
字节=atoi(纵向);
//这条线的长度是多少
longitud[MAX_MESSAGE_LENGTH]='\0';
字符*数据=新字符[字节];
n=读取(sockfd,数据,字节);
if(n<0)
错误(“错误读取输出”);
字符串ret(数据);
返回ret;
}
void客户端::closeSocket(){
关闭(sockfd);
}
您想将其硬编码到可执行文件中似乎有些奇怪。应该更灵活地使用getenv(“MY\u SERVER\u ADDR”)
之类的工具,并在运行服务器之前设置环境变量。当然,你也可以做一些更典型的事情,把它当作命令行参数,但有些事情告诉我你已经决定不这么做了
如果您在Linux上,一个稍微奇怪的想法是将IP地址写入一个文本文件,并使用
ld
和objcopy
从中创建一个ELF对象文件;然后,如果你真的想“硬编码”,你可以将其作为共享对象或静态对象加载到你的应用程序中。但我不确定为什么这比前面提到的选项更可取。您必须避开双引号:
g++ -DHOSTNAME=\"127.0.0.1\"
否则,引号只是对您的shell说127.0.0.1
是您想要给-DHOSTNAME
的值,如果该值有空格,则该值可能很有用,例如:
g++ -DMAGIC_NUMBER="150 / 5"
(此处,MAGIC_编号
将替换为不带引号的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”
。XSTR
宏允许将HOSTNAME
扩展到127.0.0.1
,然后STR
宏将其转换为“127.0.0.1”
。如果直接使用STR
宏,则最终将得到的“HOSTNAME”
,而不是“127.0.0.1”
我想我更喜欢转义解决方案,而不是在代码中使用包含两个宏的技巧,但这也行得通。客户端上的实际代码是什么。h:18?@Niall不,它说的是相同的。对不起,我忘了写我已经试过了。@BorjaArias,好的,除了你已经发布的错误内容之外,发布产生错误的实际代码也可能有用。除非你甚至没有正确复制粘贴
XSTR
技巧。第二行应该是#define STR(x)#x
。当然,你不应该盲目地将你不懂的互联网代码粘贴到生产代码中。我在一个多用户系统中工作,所以请看第二节