将结构体作为void指针传递给函数

5

我正在尝试将结构体指针传递给函数,但是当我尝试访问结构体时,结构体内的最后一个变量会丢失1个字节的内存地址,导致任何使用该变量的内容都会崩溃。

typedef struct
{
  pthread_t tID;
  int tType;
}sThread;

sThread threads[MAX_THREADS];

typedef struct
{
  int tID;
  int sock;
  int arg_count;
  char *from_p, **arg_p;
}command_struct;

pthread_t Thread_Start(void *function, void *param)
{
  pthread_t tHandle;

  pthread_create(&tHandle, NULL, function, (void*)param);

  return tHandle;
}

void cmd_test(int sock, char *from_p, char **arg_p, int arg_count)
{ 
  if(thread_check(1))
  {
    send_line(sock, "%s :test thread already running", from_p);
    return;
  }

  command_struct test;

  test.tID = thread_add(1);
  test.arg_count = arg_count;
  test.arg_p = arg_p;

  threads[test.tID].tID = Thread_Start(test_cmd, &test);
}

void *test_cmd(void *param)
{ 
  command_struct test = *((command_struct *)param);

  int i = 0;

  for(i = 1; i < test.arg_count; i++)
  {
    printf("%s", test.arg_p[i]);
  }

  thread_clear(test.tID);
  return NULL;
}

在 cmd_test 函数中(用于生成线程),正在发生的是正确初始化了结构体并且所有变量都是正确的。
$1 = {tID = 0, sock = 5, arg_count = 5, from_p = 0xbffff254 "test", arg_p = 0xbfffec48}

但是在运行线程内部的test_cmd中,结构体缺失了1个字节的arg_p地址,导致出现如下问题:

$1 = {tID = 0, sock = 5, arg_count = 5, from_p = 0xbffff254 "test", arg_p = 0xffec48}

如果我在command_struct参数的末尾添加一个无用变量,那么arg_p的地址就会变得正确,而command_struct中最后一个变量的内存地址会减少1个字节。

1
有时你使用名称 argp,有时使用 arg。这只是试图总结问题的错误吗,还是在调试器中实际上称为 argp,而在代码中称为 arg?我担心你正在调试与你想象的不同的东西,或者你包含了错误的头文件。解决这个问题的一种方法,也有助于在 StackOverflow 上发布问题,就是尝试将程序缩减到演示问题的最小示例。这样做可能会帮助你找到它;如果找不到,你可以在这里发布完整的程序,这样更容易找到问题。 - Brian Campbell
抱歉,这只是一个摘要。让我尝试将示例简化为半真实代码。 - randy newfield
还没有人说过这句话 - 从根本上讲,你正在做的事情应该是可行的。 - pm100
我不认为这会引起问题,但是Thread_Start的第一个参数应该是void *(*function)(void*) - Daniel Fischer
@pm100:有趣。我不想这么做,但我可以在结构体的末尾填充一个什么都不做的1-2字节变量,但这是一种相当糟糕的修复方式。 - randy newfield
显示剩余6条评论
1个回答

3

你正在将指向本地变量的指针传递给线程——当线程访问它时,内存已被重新用于其他用途。

尝试这样做:

void cmd_test(int sock, char *from_p, char **arg_p, int arg_count)
{ 
    if(thread_check(1))
    {
        send_line(sock, "%s :test thread already running", from_p);
        return;
    }

    // === begin modified code in cmd_test():
    command_struct* test = malloc(sizeof(command_struct));

    test->tID = thread_add(1);
    test->arg_count = arg_count;
    test->arg_p = arg_p;

    threads[test.tID].tID = Thread_Start(test_cmd, test);
    // === end modified code
}

void *test_cmd(void *param)
{ 
    command_struct test = *((command_struct *)param);
    free(param);    // <-- new line of code

    // remainder is the same...
    // ...
}

谢谢,这解决了一个问题,但却引发了另一个问题。我可以通过结构体传递整数,但是当我尝试传递指针或指向指针的指针时,在线程中结果始终为空白。(在线程启动之前在gdb中的结果看起来像$1 = {tID = 0, str = 0xbffff096 "1.2", throt = 90, p = 10, ti = 10},但我使用您修改过的代码启动线程后,它看起来像$2 = {tID = 0, str = 0xbffff096 "", throt = 90, p = 10, ti = 10}。(它修复了原始的内存问题。) - randy newfield
没关系,我设法解决了,通过将str定义为char str[18];而不是char *str,然后使用sprintf将我的arg_p变量放入其中。只是一个问题,这是因为我没有为char *str;分配空间吗? - randy newfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接