【问题标题】:Casting the void pointer and printing with format specifiers转换 void 指针并使用格式说明符打印
【发布时间】:2013-08-14 09:30:01
【问题描述】:

好的,这是针对学校项目的,但我的问题与具体实施无关,我也不寻求有关项目本身的任何帮助。我只是给出这个警告,因为我想为我正在做的事情提供上下文,但这是一个关于在项目上下文中构建 void 指针的一般性问题......我正在编写的这个函数不是甚至对于该项目,这只是我作为测试机制编写的东西,以查看我的数据结构生成是否正常......它导致我遇到涉及 printf()、格式说明符和强制转换的问题......我基本上必须实现一个链表(称为“队列”,但根本不是队列),我编写了一个函数来测试它。

基本上有一个名为“Chunk”的结构,其中包含一些变量(first 是较大数组中的索引,它是给定“Chunk”的第一个元素,而 arr 基本上是 large_array[c->first],但它实际上是一个 void 指针:void *arr 其中 c 是指向块的指针)指示更大数组中的位置。所以基本上如果你有一个像 a = {5,7,3,4,6,9,1,2} 这样的数组,并且你的块大小为 2,你有 4 个块,每个块都有一个“arr” void指针变量,分别指向5、3、6、1。

不管怎样,我写了一个“print_queue”函数(实际上是一个块的链表),耶!它会根据需要打印所有信息,这里是我将分享的核心部分:

 while (index < num_chunks) {
    first = c->first;
    printf("Chunk %d: first is %d and a[%d] is ", index, first, first);
    if (elem_size == LONG_SIZE) /* LONG_SIZE defined above as 8 */
      printf("%ld\n", c->arr);
    else if (elem_size == INT_SIZE) /* INT_SIZE defined above as 4 */
      printf("%d\n", c->arr);
    else if (elem_size == CHAR_SIZE) /* CHAR_SIZE defined above as 1 */
      printf("%c\n", c->arr);

    index++;

    if (c->next != NULL)
      c = c->next;
 }

我基本上想编写一个函数,该函数能够在我实现项目的实际功能(多线程合并-种类)。所以上面的代码确实有效!这是此数组输入的输出:

 char original[] = {'z', 'y', 'x', 'w', 'v', 'u', 't', 's'};

输出:

 Chunk 0: first is 0 and a[0] is z
 Chunk 1: first is 2 and a[2] is x
 Chunk 2: first is 4 and a[4] is v 
 Chunk 3: first is 6 and a[6] is t

所以它起作用了!耶!但是,我收到以下编译器警告:

mergesort.c: In function 'print_chunk_queue':
mergesort.c:85:7: warning: format '%ld' expects argument of type 'long int', but     argument 2 has type 'void *' [-Wformat]
mergesort.c:87:7: warning: format '%d' expects argument of type 'int', but argument 2 has type 'void *' [-Wformat]
mergesort.c:89:7: warning: format '%c' expects argument of type 'int', but argument 2 has type 'void *' [-Wformat]

所以我所做的是将所有 c->arr 转换为 (type *) c->arr,但这给了我更多关于“哦,我们想要一个 int 但你有一个 int 指针”的警告,那又如何我当时做的是:

 * ((type *) c->arr)

基本上取消引用我的强制转换的 void 指针(它永远不会为空!它总是指向有效数字,至少在我提供的输入中是这样!),然后这给了我一个分段错误!。所以我很沮丧,因为我从带有大量“警告”的工作输出变成了无用的分段错误。

编辑:

根据要求定义数据结构:

typedef struct chunk {
  void *arr;
  struct chunk *next;
  int first;
} Chunk;

这就是我设置单个块的状态并创建块的链接列表的方式:

  while (index < number_of_chunks) {
    if (index == 0) {
      if ((current = malloc(sizeof(Chunk))) == NULL)
        err(EX_OSERR, "memory allocation has failed\n");
      head = current;
    }
    current->first = (chunk_size * index);
    current->arr = ((char *) array)[current->first];
    current->size = chunk_size;
    if (index != (number_of_chunks - 1)) {
      if ((current->next = malloc(sizeof(Chunk))) == NULL)
        err(EX_OSERR, "memory allocation has failed\n");
      current = current->next;
   }
  else {
    tail = current;
  }
  index += 1;
}

【问题讨论】:

  • 你能发布数据结构的定义吗?
  • 你如何设置arr?请显示该代码。令人担忧的是,printf("%c\n", c-&gt;arr) 实际上会打印正确的值,因为c-&gt;arr 应该是地址,而不是char
  • 我应该在人们提问时继续编辑我的帖子,还是最好的方法是什么?我无法在 cmets 中发布代码
  • @JohnKugelman 我发布了块和链表的初始化代码
  • @Windows 是的,编辑您的帖子,这是最好的方法。为反应如此迅速而干杯!

标签: c casting segmentation-fault void-pointers


【解决方案1】:
current->arr = ((char *) array)[current->first];

这里应该有一个&amp;。您想将字节的地址分配给arr,而不是它的

current->arr = &((char *) array)[current->first];

如果您这样做,那么arr 将包含一个应有的地址,这将允许强制转换和取消引用工作。

printf("%ld\n", *(long *) c->arr);
printf("%d\n",  *(int  *) c->arr);
printf("%c\n",  *(char *) c->arr);

【讨论】:

  • 第一个需要长双吗?我尝试使用格式说明符 %l 但我的编辑说它不存在,所以我使用了 %ld 因为我以前见过那个,但后来 gcc 告诉我 (long *) 是不允许的,或者不对应告诉?非常感谢您的洞察力,我将数组元素分配给指针是非常愚蠢的,所以我感谢您的帮助
  • 对不起^^我的意思不是long double 我的意思是(long int *),但我会再试试你说的。
  • 天哪,它有效。非常感谢约翰·库格曼!你知道为什么 int 和 long 使用 d 作为格式说明符吗?附言(长*)确实有效,哈哈。谢谢!!!!!!!!!!!!!!!!!!
  • int 使用dlong 使用 ld。只是碰巧在您的环境中“int”和“long”可能是相同的。情况并非总是如此。如果它们确实起作用并且尺寸不同,则它的UB(薄冰)。
  • d 代表“十进制”。 %i%d 的同义词。无论出于何种原因,%d%i 更受欢迎。
猜你喜欢
  • 1970-01-01
  • 2023-03-20
  • 2016-08-15
  • 2021-07-13
  • 1970-01-01
  • 2015-12-31
  • 1970-01-01
相关资源
最近更新 更多