在一个char *中连接包含可变大小数据的结构

时间:2014-05-28 17:07:48

标签: c struct printf

我有一个结构:

typedef struct message
{
    char* dchatver;
    int contype;
    int conlen;
    char* context;
} message_t;

我需要一个函数来获取指向已填充message_t的指针,该函数会将message_t写入文件描述符。 message_t可以包含dchatver = "DCHAT:1.0"; contype = 3; conlen = 6; context = "hello";我希望将其连接到一个char[totallength],看起来像" DCHAT:1.0\n3\n6\nhello\n"

我的问题是如何将dchatvercontypeconlencontext连接到一个char*,以便将其用于写入?我考虑过使用snprintf,但我不知道如何确定给定message_t的长度。

5 个答案:

答案 0 :(得分:1)

void WriteMessage(int fd, message_t *message)
   {
   char *writeBuf=NULL;
   size_t writeBufSize;

   /* Determine the size of the output string. */
   writeBufSize = 1 + snprintf(NULL, 0, "%s\n%d\n%d\n%s\n",
         message->dchatver,
         message->contype,
         message->conlen,
         message->context
         );

   /* Allocate memory for the string */
   writeBuf = malloc(writeBufSize);

   /* Initialize the string. */
   snprintf(writeBuf, writeBufSize, "%s\n%d\n%d\n%s\n",
         message->dchatver,
         message->contype,
         message->conlen,
         message->context
         );

   /* write the record */
   write(fd, writeBuf, writeBufSize - 1);

   free(writeBuf);

   return;
   }

答案 1 :(得分:0)

您可以使用dchatver找到contextstrlen的长度。要查找contypeconlen的长度比较困难,但您可以采取捷径。您可以使用以下方法计算其最大长度,而不是查找这些特定字段的长度:

#include <limits.h>

#define INT_STR_LEN_UPPER_BOUND (sizeof (int) * CHAR_BIT * 3.4)

因此,您可以为每个int字段分配这么多空间,将其传递给snprintf,然后在其上使用strlen来获取整个字符串的实际长度。像这样:

size_t s = strlen (msg->dchatver) + strlen (msg->context) + 
    sizeof (int) * 54.4 + 4;
char *out = calloc (s, sizeof *out);
snprintf (out, s, "%s %d %d %s", msg->dchatver, msg->contype, 
          msg->conlen, msg->context);

答案 2 :(得分:0)

我正在解释这意味着您要将变量值打印到屏幕上。

如果您确定每个char *都正确地以null结尾,则可以使用sprintf()而不是snprintf()。

例如,这将在新行上打印出每个变量,其中的字符串用引号括起来:

char buf[256]; // make sure this buffer is large enough
message_t msg;

//
// assuming the variable 'msg' gets filled in here
//

sprintf(buf, "dchatver = \"%s\"\ncontype = %d\nconlen = %d\ncontext = \"%s\"\n", 
   msg.dchatver, 
   msg.contype, 
   msg.conlen, 
   msg.context);

// print the string to console, or do other stuff
printf("%s\n", buf);

答案 3 :(得分:0)

这是一个可以将message_t转换为您想要使用的格式的字符串的函数。

char* messageToString(message_t m)
{
   char buffer1[50]; // If your numbers can occupy more than 50 spaces, 
   char buffer2[50]; // these will have to be updated.
   char* ret = NULL;
   size_t len = 0;

   sprintf(buffer1, "\n%d", m.contype);
   sprintf(buffer2, "\n%d\n", m.conlen);
   len = strlen(m.dchatver) + strlen(buffer1) + strlen(buffer2) + strlen(m.context);
   ret = malloc(len+2); // One extra for the newline. One extra for the null

   strcpy(ret, m.dchatver);
   strcat(ret, buffer1);
   strcat(ret, buffer2);
   strcat(ret, m.context);
   strcat(ret, "\n");

   return ret;
}

确保在返回的值上调用free以防止内存泄漏。

答案 4 :(得分:0)

诀窍在于,您不必知道格式化消息字符串的长度,您只需要一个上限即可。并且您知道格式化的消息永远不会超过strlen(dchatver) + 10(对于contype)+ 10(对于conlen)+ conlen(对于上下文)+ 3(对于&#39; \ n&#39 ; S)。 (conlen显然包含尾随null的空间,因此我们不必为此添加一个空格,但为了以防万一,它可能是好的。)

幻数10假设你的int类型是32位,并且总是正数,如果这些不是安全的假设,你必须做更多的数学运算。

我喜欢这样做是为了灵活性。 (我的C生锈了,所以这里可能存在语法错误)

//this allows you to format to preallocated buffers, saving you
//allocation overhead, and possibly copy overhead
int printf_message(char* buffer, int len, message_t* msg) 
{
    assert(msg->conlen == strlen(msg->context)+1); //just in case
    int r = snprintf(buffer, len, "%s\n%d\n%d\n%s\n",
            msg->dchatver, msg->contype, msg->conlen,  msg->context);
    return r;
}

//this is slightly easier to use, with a small potential overhead
//free the return pointer with "free" when you're done
char* get_formatted_message(message_t* msg) 
{ 
    //contype is a 32bit positive integer, and therefore a maximum of 10 digits 
    //conlen is a 32bit positive integer, and therefore a maximum of 10 digits
    //we need 3 '\n's, and one '\0'.
    int len = strlen(msg->dchatver) + conlen + 24;
    char* buffer = malloc(len);
    if (buffer) 
    {
        printf_message(buffer, len, msg);
    }
    return buffer;
}