【问题标题】:Passing char* as a parameter to dynamically called function gives runtime error将 char* 作为参数传递给动态调用的函数会产生运行时错误
【发布时间】:2013-08-05 17:34:48
【问题描述】:

我有一个名为 testdynamic 的函数,它使用 dlopen 和 dlsym 动态调用。现在,我创建了一个结构:

typedef struct BigStruct{
    char el[2000];
}BigStruct;

用于存储函数的参数。然后,我将空间分配给一个名为:

void *cur = (void*)malloc(totalSize);

其中,totalSize 是参数的大小。我事先有这个信息。

之后,我将所有参数复制到 cur。

然后,我将它转换为 BigStruct,如下所示:

BigStruct *bg;
bg = (BigStruct*)cur;

然后像这样运行它:

void* ch = (void*)testdynamic(*bg);

现在,当我打印参数时,在函数 testdynamic 中,我得到了所有数据类型的正确值,例如 char**int*、int 等。

唯一不起作用的数据类型是 char*。即使在使用*bg 调用函数之前,bg->el 的内容对于 char* 也是正确的。但是,调用后,出现错误。

可能是什么问题?

这里是testdynamic的代码

char* testdynamic(char* x, char* y){
    printf("%s %s\n", x, y);
    return "hello";
}

我想从我的代码中将参数传递给函数 testdynamic。
这个 testdynamic 可以是可以接受任何类型的任何参数的任何函数。
我在运行时获得有关该函数的信息。由于 char* 的大小为 1,我将所有内容都转换为 char*,然后将其传递给函数。
此时,如果我在 testdynamic 中打印 char* 类型的任何内容,我会收到运行时错误。

【问题讨论】:

  • 请提供更多信息!
  • 还需要什么信息?我将编辑我的问题。
  • 你得到什么样的错误?您是否尝试过在调试器下运行代码?您的“打印参数”如何? testdynamic 的声明是什么样的?你如何在其中填充论点?为什么要将堆栈上BigStructCOPY 传递给testdynamic?您如何在testdynamic 中“消除”参数?你怎么处理这些论点?等等。
  • 您不需要强制转换,因为与void * 之间的所有转换都会自动转换为适当的类型。
  • 1) 给出失败输出的示例。 2)由于*bg在testdynamic(*bg)之前好,之后不好,请提供testdynamic()代码。

标签: c gcc runtime-error


【解决方案1】:

您假设 BigStruct 看起来与 2000 个字符的数组完全一样。这取决于编译器,不太可能是真的。我猜您真的想将 cur 指向的数据复制到 el 数组中,而不是将其全部写入 BigStruct 本身,BigStruct 本身将具有一些您不知道的内部存储格式。

【讨论】:

  • 由于 sizeof char* 为 1,所以我将类型转换为 BigStruct。它适用于所有其他类型。
  • 即使它有时对 Rishi 有效,但这并不是编写将内容复制到结构中的代码的方法。它对编译器如何存储它们做出了太多假设。它只编译是因为您使用了 void * 指针,并且容易出现各种内存覆盖错误。
  • 它在某些时候有效并不意味着它是正确的。吃生肉也可以……除了有时,当你吃鸡肉时,会发生非常糟糕的事情。
【解决方案2】:

如果是totalSize > sizeof(BigStruct),您将遇到问题,因为您没有将数据的完整副本传递给testdynamic(),可能会弄乱副本并因此未定义的行为

如果totalSize < sizeof(BigStruct),当您将*bg 传递给testdynamic() 时,您在读取不属于您的内存空间时遇到问题 - 因此未定义行为

你更安全

bg = malloc(*bg);

这里还有其他有问题的程序问题,但需要更完整的帖子。

【讨论】:

    【解决方案3】:

    又看了几遍……

    您正在为需要 2 个参数的函数传入一个参数。

    您是否使用 -Wall 在编译期间将警告视为错误?第二个参数没有传入,即参数 y 为空。访问 null 会导致问题。

    【讨论】:

      【解决方案4】:

      所以总结一下我理解你在做什么:

      • 将 cur 视为 char* 并将参数列表复制到其中
      • 将 cur 转换为 BigStruct*,然后将其传递给 testdynamic 函数。

      在我看来,这似乎是一种奇怪的处理方式,如果不查看 testdynamic 函数内部,我会猜测这是导致错误的原因。我建议更改您对 BigStruct 的定义:

      typedef struct {
          char * el;
      } BigStruct;
      

      这样,您可以为您的 char 数组分配空间,将您的参数列表复制到其中,然后将 BigStruct 中的 char * 设置为指向相关的内存块,如下所示:

      char * cur = malloc(totalSize);
      // Copy parameters over into cur
      BigStruct * bg = malloc(sizeof(BigStruct));
      bg->el = cur;
      

      然后再次调用您的 testdynamic 函数。试试这个,你还会遇到运行时错误吗?

      编辑:看过 testdynamic 函数的内容后,我发现它有几个问题

      char* testdynamic(char* x, char* y){
          printf("%s %s\n", x, y);
          return "hello";
      }
      
      1. 该函数接受 2 char * 但您似乎只在代码中传递了 1。如果你只给它一个 x 的参数,它应该为 y 打印什么?
      2. 假设您现在正在传递 x 和 y 的参数。您确定两个字符串都以空字符结尾吗? printf 的工作原理是打印字符,直到找到 '\0' 字符。
      3. 您不能只从这样的函数中返回字符串文字。该字符串文字属于该函数,一旦函数返回,您无法保证保存该字符串的内存仍然可以安全地再次访问。如果你想返回一个这样的字符串,你应该首先 malloc() 为字符串分配空间并将地址返回到分配的内存块。

      【讨论】:

      • 您的第 3 点是错误的。 return "hello" 完全有效。将其作为char* 返回在技术上是错误的,因为字符串文字的类型为const char *,但这不是致命错误。
      • 感谢@NikBougalis 向我指出这一点,我仔细检查并发现this thread 为我进一步澄清了这一点。
      • @NikBougalis 说字符串文字是const char * 类型是不正确的。由于历史原因,字符串文字在 C 中没有 const 类型。修改它们仍然是未定义的行为。
      • @ElchononEdelson 感谢您指出这一点;另一个需要记住的 C 和 C++ 之间的细微差别。
      【解决方案5】:

      为了提供准确、中立的 cmets,需要提供一份代码副本。因此,我采用了您的 cmets 并生成了以下代码。这可能不是您想要做的。但是,应该逐步或增量地处理编程问题。

      也就是说,先做一些简单的工作,然后让它变得更复杂一些,但仍然可以工作,并朝着最终版本的方向努力。这就是我们许多人的工作。没有人能够在第一次正确地编写复杂的程序,尤其是对于这门语言的新手!

      #include <stdio.h>
      #include <stdlib.h>
      char *testdynamic(char *x, char* y){
      
              printf("%s %s\n", x, y);
              return "hello";
          }
      
      main()
      {
          typedef struct BigStruct{
              char el[2000];
          } BigStruct;
      
          char      *ret_char_ptr;
      
          BigStruct *bg;
      
          char x[] = "abcd";
          char y[] = "23456";
      
          bg = malloc(sizeof(BigStruct));
      
          // invoke the testdynamic function
          ret_char_ptr = testdynamic(x, y);
      
      
          printf("%s\n", ret_char_ptr);
      
      }
      

      我在 Eclipse/Microsoft C 编译器上运行了这段代码,得到了以下输出:

      abcd 23456
      hello
      

      注意。 BigStruct 尚未在此代码中使用。不确定您的意图是什么,但 C 确实提供了一种将长度不同的参数列表和来自多个不同调用的数据传递给同一函数的方法。

      【讨论】:

      • 函数testdynamic是动态加载的。你为什么要传递x,y给它?请看看当你将 bg 传递给它时会发生什么。
      【解决方案6】:

      这仅适用于大小为sizeof(BigStruct)

      你不能假设一个结构就是它的内容的大小,因为编译器可能会做出对齐等假设。

      如果您只想要 20,000 个字符,然后像其他人建议的那样将其 malloc 到 BigStruct 中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-12-23
        • 2019-01-25
        • 2018-04-21
        • 2011-04-14
        • 2021-05-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多