只是尝试创建一个简单的toString函数,但我很难弄清楚如何创建sprintf样式字符串而不必创建临时变量。
即。如果以下工作将会很棒
#myfile.c
bool status;
int state;
...
const char* myfileToString(void) {
return sprintf("myfile::status=%s;state=%d;", \
status ? "true" : "false", \
state);
}
这不起作用,因为sprintf需要您先创建字符串然后将其传递给函数。
即。我相信以下工作
#myfile.c
bool status;
int state;
...
const char* myfileToString(void) {
char ret[40];
sprintf(ret, \
"myfile::status=%s;state=%d;", \
status ? "true" : "false", \
state);
return ret;
}
是否有另一个我可以使用的函数而不是sprintf,或者我可以使用sprintf做一些奇怪的事情,比如传递一些指针直接返回sprintf(*return, "...", ...);
答案 0 :(得分:5)
好了...
sprintf()
需要一个可变缓冲区作为它的第一个参数。你没有通过,所以你会在这里得到各种不良行为。在此功能之外分配内存。所以:
void myfileToString(const char *str, size_t len) {
snprintf(str, len, "myfile::status=%s;state=%d;",
status ? "true" : "false",
state);
str[len - 1] = '\0';
}
你可以这样做:
char box[40];
myfileToString(box, sizeof(box) /* 40 */);
sprintf()
函数族返回写入缓冲区的字符数。如果写入的字符数大于缓冲区的大小,您可以使用它来发回错误(例如,返回true或false)。
这不是最好的做法,因为它会弄乱人们的期望。但是您可以在堆上为此数据分配内存。你需要记得将来再打电话给free()
。
const char *myFileToString() {
char *str = malloc(40);
snprintf(str, 40, "myfile::status=%s;state=%d;",
status ? "true" : "false",
state);
str[40 - 1] = '\0';
}
答案 1 :(得分:1)
在第一个版本中,您返回sprintf
返回的内容,这将无效,因为它实际上不会返回字符串(请阅读链接的引用)。在函数的第二个版本中,您返回一个指向局部变量的指针,这会导致undefined behavior,因为当函数返回并且指针不再指向有效内存时,局部变量超出范围。
有两个主要解决方案:
动态分配字符串,例如使用malloc
,并返回该指针。主要缺点是你必须free
你返回的指针。
将字符数组作为参数传递给函数,并将其用作字符串的目标。
此外,您应该使用snprintf
而不是普通sprintf
,因为这样您就可以控制写入目标字符串的数量,因此您不会获得缓冲区溢出。在使用Visual C ++编译器的Windows上,它称为_snprintf
。
答案 2 :(得分:1)
您不想使用本地变量来构建您的sting。一旦返回,变量将丢失,您的返回值将是未定义的。相反,您可以使用malloc()
在例程中分配内存,也可以将指向预分配内存的指针传递到例程中。
在任何一种情况下,您都应该使用snprintf()
代替sprintf()
,以确保不会溢出缓冲区。
答案 3 :(得分:0)
您不能在函数中返回char [],因为它是静态分配的(在您的堆栈上)并在函数结束时销毁。对于你的toString函数,你必须使用malloc来返回动态分配的char *(在你的堆中)
答案 4 :(得分:0)
你的第一种方法完全错了!你不应该这样使用!
您可以使用sprintf
snprintf
snprintf(ret,sizeof(ret),"myfile::status=%s;state=%d;",status ? "true" : "false",state);
答案 5 :(得分:0)
我使用这个(非常讨厌的)技巧:
struct strang
{
char s[100] ; /* this is arbitrary, but has to be enough ! */
} ;
并且,举例来说,将struct sockaddr
转换为合适的字符串:
struct strang
sockaddr2strang(struct sockaddr* sa)
{
struct strang str ;
struct sockaddr_in* sin ;
....
switch (sa->sa_family)
{
AF_INET:
sin = (struct sock_addr_in*)sa ;
inet_ntop(AF_INET, &sin->sin_addr, str.s, sizeof(str)) ;
break ;
....
} ;
return str ;
} ;
狡猾的部分是你可以在表达式中使用结果或作为另一个函数的参数,例如:
printf("....%s..%s..", ...., sockaddr2strang(&sa_local).s,
...., sockaddr2strang(&sa_peer).s) ;
请注意,这完全是pthread-safe,并且不需要调用者设置和传入任何辅助缓冲区 - 特别是(如此处所示)如果同时需要多个字符串,来电者不必管理两个(或更多)缓冲区等。
显然,这对任意大小的返回字符串都不起作用。