gpointer转换为gint *导致分段错误 - 为什么?

时间:2015-02-18 11:45:16

标签: c pointers glib

我试图在C中学习使用void指针。这里是我用GLib编写的代码:

#include <stdio.h>
#include <gtk/gtk.h>

int
main (void)
{
  GList *l = NULL;
  l = g_list_append (l, GINT_TO_POINTER (1));
  l = g_list_append (l, GINT_TO_POINTER (2));
  l = g_list_append (l, GINT_TO_POINTER (3));
  GList *l1 = g_list_nth (l, 1);
  gpointer snd_element = (l1->data);
  gint *digit = snd_element;
  gint forty_two = 40;
  forty_two = forty_two + *digit;
  printf ("%d\n", forty_two);

  return 0;
}

我希望这个程序的行为是打印42.不幸的是,运行它会导致分段错误。为什么呢?

2 个答案:

答案 0 :(得分:2)

g_list_append期望传递要存储的数据的指针。 GINT_TO_POINTER只是将给定的整数转换为指针(即它基本上是(gpointer)x),因此指针实际上并不指向任何有效数据,它只是一个数字。将数据添加到列表后,指针将具有值1,2和3。

假设g_list_nth成功,l1->data将是之前传递给g_list_append指针。在这种情况下,指针的值将为2(指向的值)。然后,您尝试取消引用此指针,这将导致分段错误。

相反,只需将其直接转换回int并且不要取消引用以获取值。您应该使用提供的反向宏GPOINTER_TO_INT,例如

gpointer snd_element = (l1->data);
gint digit = GPOINTER_TO_INT(snd_element); // Note I've removed the *...
gint forty_two = 40;
forty_two = forty_two + digit; // Note I've not attempted to dereference it

答案 1 :(得分:2)

此:

gpointer snd_element = (l1->data);

使snd_element包含值2,但转换为指针。这很可能是您的流程的有效内存地址。

所以这个:

forty_two = forty_two + *digit;

取消引用digit会导致未定义的行为。

你应该这样做:

const int forty_two = 40 + GPOINTER_TO_INT(digit);