c函数返回sprintf字符串

时间:2014-07-29 15:30:40

标签: c string

只是尝试创建一个简单的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, "...", ...);

6 个答案:

答案 0 :(得分:5)

好了...

第1部分:

  • 除非您正在编写宏,否则在未完成的行末尾不需要反斜杠。
  • sprintf()需要一个可变缓冲区作为它的第一个参数。你没有通过,所以你会在这里得到各种不良行为。

第2部分:

  • 您正在返回指向堆栈分配对象的指针。这将导致未定义的行为。

你应该做什么:

在此功能之外分配内存。所以:

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,因为当函数返回并且指针不再指向有效内存时,局部变量超出范围。

有两个主要解决方案:

  1. 动态分配字符串,例如使用malloc,并返回该指针。主要缺点是你必须free你返回的指针。

  2. 将字符数组作为参数传递给函数,并将其用作字符串的目标。

  3. 此外,您应该使用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,并且不需要调用者设置和传入任何辅助缓冲区 - 特别是(如此处所示)如果同时需要多个字符串,来电者不必管理两个(或更多)缓冲区等。

显然,这对任意大小的返回字符串都不起作用。