【问题标题】:incorrect pointer value passed to a C function传递给 C 函数的指针值不正确
【发布时间】:2015-08-07 17:21:58
【问题描述】:

我有一个错误,其中不正确的值作为参数传递给 C 程序中的函数。它的工作方式是,我将一个指向 typedef 数据结构的静态指针声明为全局变量。有一个初始化函数,用于初始化此变量。该函数分配内存、初始化数据字段并返回指针。像这样的:

static my_type *my_ptr;
...
void init(void){
   my_ptr = init_my_type();
}

init_my_type 函数非常简单:

void *init_my_type(void){
   my_type *x = malloc(sizeof(my_type);
   x->arg1 = 0;
   ... // more field initializations
   return x;
}

稍后我使用my_ptr 作为另一个函数的参数:

void do_stuff(void){
   func(my_ptr);
}

我遇到的问题是,当访问my_ptr 指向的数据结构中的某些数据时,我在func 的内部出现了段错误。

当我运行调试器时,当我在init_my_type 上中断时,我会得到一个漂亮的十六进制值:

(gdb) finish
Value returned is $26 (void *) 0x79b6c0

稍后,在do_stuff 函数内部,my_ptr 具有相同的十六进制值:

(gdb) print my_ptr
$26 = (my_type *) 0x79b6c0

但是,当我打破func 时,它得到的论点具有完全不同的价值。

Breakpoint 2, func(arg=0x1388)

我到处都是类型双关语指针,但我认为这不会改变它们指向的内存地址,对吧?此外,函数func 被声明为inline,但为什么会影响这个呢?这一切对我来说似乎都是正确的——我完全有可能在做一些我看不到的愚蠢的事情。

这里是简化代码的完整程序。实际上,所有这些函数都不是由 main 调用的,而是由动态加载的辅助函数调用的。不过,我看不出my_ptr 指向的地址在传递给func 时应该如何变化。

#include "stdlib.h"
#include "stdio.h"

typedef struct _type{
  int *i1;
  float *f1;
}my_type;

static my_type *my_ptr;

void *init_my_type(void){

  my_type *x = malloc(sizeof(my_type));
  x->f1 = malloc(sizeof(float));
  x->i1 = malloc(sizeof(int));
  x->f1[0] = 123.456;
  x->i1[0] = 789;

  return x;

}

void init(void){

  my_ptr = init_my_type();

}

inline void func(void *arg){

  my_type *x = (my_type *)arg;
  printf("%d %f\n", *x->i1, *x->f1);

}

void do_stuff(void){

  func(my_ptr);

}


int main(void){

  init();
  do_stuff();


}

【问题讨论】:

  • 请在minimal, complete, verifiable example 上发布您遇到的问题。到目前为止,根据这里的小代码,不可能知道发生了什么。
  • @dmedine,您不会在出现错误的地方提供func。你认为我们应该如何猜测这个。 MCVE 对我们来说真的很重要,这样我们就可以快速检查发生了什么,这对您也很重要,因为它有助于澄清您的代码。
  • 扩展 bpgeck 的注释,在与 bug 实际位置完全无关的部分代码中可能会发生 seg 错误。这就是为什么需要一段显示问题的可编译代码的原因。
  • 在这种情况下,我建议在 valgrind 下运行您的代码。如果你正在访问你不应该访问的内存,它会告诉你。
  • 我猜你是在 64 位平台上编译,init_my_type 没有在调用时声明(在init 内)。编译器假定它返回 int 并将 64 位指针值修剪为 32 位 int 值。这个修剪后的值随后被传递给func。如果是这种情况,那么您一定忽略了编译器发出的一堆警告。

标签: c pointers inline type-punning


【解决方案1】:

以下不是问题的原因(也不能,因为静态全局变量默认初始化为零)。尽管基本思想仍然相关:传递的指针是否真的与初始化的相同。


一个疯狂的猜测:

static my_type *my_ptr;

这行可能是某些头文件的一部分吗?因为在每个包含此标头的源文件中都有一个全局 my_ptr

既然你写了这是一个非常大的项目,我假设你将代码分开并放入多个源文件中。假设 init 函数与 using 函数位于不同的源文件中,那么这意味着它们正在访问不同的指针。当init 处理的那个被初始化时,func 正在使用的那个是未初始化的。

要检查这一点,您应该在两个函数中打印全局指针变量 (&my_ptr) 的地址。

【讨论】:

  • 嗯。 my_ptr 在调用 func 的同一文件中声明。 init_my_func 在不同的文件中,但 init 不在。根据我的(有限)理解,由于my_ptrinit在同一个文件中声明,那么init_my_funcinit调用)返回的值就OK了。
  • 好吧,那我猜错了。但是,您能否在 init 和 use 时打印(从实际代码,而不是调试器)指针的地址?
  • 如果 func() 看到的不同值是零,静态的东西是有意义的,因为 C 定义静态变量在被引用之前自动初始化为零。然而,事实并非如此。
  • 确实,仍然是@dmedine,我认为知道您在两个地方使用相同的全局变量会很有帮助,在“通过动态加载的辅助函数调用 [...] 的上下文中。 "
  • @Daniel Jour 我已经在两种情况下都打印了指针,它们看起来都是正确的。调试器中的一些有趣的东西——或者(更有可能)我没有正确使用让我陷入了一场猎捕。这个虫子显然在别处,可能不像我担心的那么神秘。虽然,它仍然很难追踪。
猜你喜欢
  • 1970-01-01
  • 2013-10-27
  • 2020-12-10
  • 1970-01-01
  • 2013-09-17
  • 2012-02-22
  • 2013-04-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多