Memcpy字符串作为void指针,读取错误

时间:2013-05-02 17:09:24

标签: c pointers buffer memcpy

我正在尝试创建一个将任意类型的缓冲区组合在一起的函数。想想基本的RPC。所以缓冲区看起来像

{ char opcode, uint32_t param1_size, param1, ... , uint32_t paramN_size, paramN }

它似乎正在工作但是当从缓冲区中提取数据时,它似乎没有正确地解释字符串。

int enqueue_into_buf(char *buf, size_t buf_pos, const uint32_t param_len, const void *param) {

    /* If param_len is NULL, then change opcode */
    if(param_len == 0) {
        memcpy( buf, param, 1 );
        if(buf_pos == 0)
            buf_pos++;
        return buf_pos;
    }

    memcpy( buf + buf_pos, &param_len, sizeof(param_len) );
    buf_pos += sizeof(param_len);

    memcpy( buf + buf_pos, param, param_len );
    buf_pos += param_len;

    return buf_pos;
}

int main(int argc, char *argv[])
{
    char opcode;
    uint32_t param_len, num_params, buf_size, buf_pos = 0, received_num;
    char *buf, *temp;

    char *input_string = "file01"; /* example string to use as parameter */
    size_t input_size = 4, received_size; /* example variable to also use as a parameter */

    opcode = '1'; /* opcode equals function 1 */
    num_params = 2; /* number of parameters */

    /* setting the size of the buffer that will be sent over the network */
    buf_size = sizeof(opcode) + ( num_params * sizeof(uint32_t) ) + (strlen(input_string) * sizeof(char)) + sizeof(input_size);
    buf = malloc( buf_size );

    /* Notice the ampersand! */
    buf_pos = enqueue_into_buf(buf, buf_pos, 0, &opcode);
    buf_pos = enqueue_into_buf(buf, buf_pos, strlen(input_string), &input_string);
    buf_pos = enqueue_into_buf(buf, buf_pos, sizeof(input_size), &input_size);

    /* At this point, since we inserted everything into the buffer, 
    the buffer size and current buffer position should be equal */ 
    if(buf_pos == buf_size)
        printf("Calculated buffer size correctly and inserted everything correctly as well. Buffer size = %d\n", buf_size);

    /** Extract from buffer **/
    buf_pos = 0;

    printf("Opcode: %c\n", buf[buf_pos]);
    buf_pos++;

    memcpy(&received_num, buf + buf_pos, sizeof(uint32_t));
    printf("Size of parameter 1: %d\n", received_num);
    buf_pos += sizeof(uint32_t);

    temp = malloc(received_num + 1);
    memcpy(temp, buf + buf_pos, received_num);
    temp[received_num] = '\0';
    printf("Parameter 1: %s\n", temp);
    buf_pos += received_num;

    memcpy(&received_num, buf + buf_pos, sizeof(uint32_t));
    printf("Size of parameter 2: %d\n", received_num);
    buf_pos += sizeof(uint32_t);

    memcpy(&received_size, buf + buf_pos, sizeof(size_t));
    printf("Parameter 2: %d\n", received_size);
    buf_pos += sizeof(size_t);

    return 0;
}

编辑:输出代码:

Calculated buffer size correctly and inserted everything correctly as well. Buffer size = 23
Opcode: 1
Size of parameter 1: 6
Parameter 1: @  @
Size of parameter 2: 8
Parameter 2: 4

我认为我没有正确地将数据复制到缓冲区中,因为使用相同的参数(input_string =“file01”,input_size = 4),此代码可以正常运行...

    /* OPCODE */
    buf[buf_pos] = opcode;
    buf_pos++;

    /* PARAMETER 1 */
    param_len = (strlen(input_string) * sizeof(char)); /* size of parameter 1 */

    memcpy(buf + buf_pos, &param_len, sizeof(uint32_t));
    buf_pos += sizeof(uint32_t);

    //memcpy( buf + buf_pos, &input_string, (strlen(input_string) * sizeof(char)) );
    strcat( buf + buf_pos, input_string );
    buf_pos += strlen(input_string) * sizeof(char);


    /* PARAMETER 2 */
    param_len = sizeof(input_size);

    memcpy(buf + buf_pos, &param_len, sizeof(param_len)); /* same as saying sizeof(uint32_t) */
    buf_pos += sizeof(uint32_t);

    memcpy(buf + buf_pos, &input_size, sizeof(input_size));
    buf_pos += sizeof(input_size);

编辑:输出代码:

Calculated buffer size correctly and inserted everything correctly as well. Buffer size = 23
Opcode: 1
Size of parameter 1: 6
Parameter 1: file01
Size of parameter 2: 8
Parameter 2: 4

但显然我不想使用strcat(),因为我不知道它将是什么类型的数据。我不正确地使用memcpy吗?

编辑:输出节目输出

2 个答案:

答案 0 :(得分:1)

您自己突出了问题:

/* Notice the ampersand! */
buf_pos = enqueue_into_buf(buf, buf_pos, 0, &opcode);
buf_pos = enqueue_into_buf(buf, buf_pos, strlen(input_string), &input_string);

您已宣布

char *input_string = "file01";

因此,当您将&input_string传递给enqueue_into_buf时,您将从指针strlen(input_string)存储到缓冲区的位置复制input_string个字节。

通常,在64位系统上,这将是指针值的八个字节中的六个,在32位系统上,指针的四个字节加上后面的两个字节(调用未定义的行为)。

但是你想将字符串"file01"复制到缓冲区,即指针指向的位置,因此你不能传递指针的地址而是指针本身:

buf_pos = enqueue_into_buf(buf, buf_pos, strlen(input_string), input_string);
                                                           // ^^ No address taken here!

答案 1 :(得分:1)

这里有几个问题。

首先:

buf_pos = enqueue_into_buf(buf, buf_pos, strlen(input_string), &input_string);

你试图将第四个参数传递给enque作为void *一个字符串已经是一个指针类型,所以传递字符串的地址是而不是你想要的做,只是:

buf_pos = enqueue_into_buf(buf, buf_pos, strlen(input_string), input_string);

是对的。

第二:

你永远不会把你的buf归零,所以你不知道那里坐着什么:

buf = malloc( buf_size );
memset(buf, 0, buf_size);  // add this line here to clear the buffer before using it

声明,分配,初始化......然后使用。它会为你节省很多麻烦。