【问题标题】:void* vs. char* pointer arithmeticvoid* 与 char* 指针运算
【发布时间】:2012-04-07 20:45:51
【问题描述】:

我正在翻阅我的教科书,我对其中的一些代码感到有些困惑。一方面,他们通过以下方式执行指针运算:

void* bp;
...
bp = (void*)((char*)(bp)+16);
...

但稍后,他们会执行以下操作:

void* bp;
...
bp = bp+16;
...

我觉得他们应该是两个不同的东西,但他们把它当作同一个东西对待。 我有这种感觉是因为,例如,如果您要进行数组访问(例如,对于整数数组),您将执行以下操作

int* a = malloc(n*sizeof(int));
...
q = *(a+1);
...

在这种情况下,我不是访问整数数组中接下来的 4 个字节而不是下一个字节吗? 同样,我觉得如果我有 void* a,那么 *(a+1) 应该是接下来的 4 个字节...... 或者事实并非如此? 谢谢。

【问题讨论】:

  • 第二个例子不应该编译。
  • @OliCharlesworth:如果您在一致模式下编译,它将不会编译(或至少会触发警告)。 gcc 默认情况下不符合,并实现void* 算术作为扩展。

标签: c pointers pointer-arithmetic


【解决方案1】:

这是一个失误。 void * 的算术不是由标准定义的,但一些编译器将其作为扩展提供,其行为与 char * 的算术相同。第二个在形式上不是有效的 C,但可能是出于(坏)习惯。

【讨论】:

  • 所以访问下一个 16 字节的正确方法是首先转换为 char* 然后添加 16?大声笑,现在必须更改大量代码。哦,我复制了第一个有点错误,我做了一个小改动,但我认为这不会对我的问题产生影响。
  • 或者您可以转换为uint64_t * 并添加 2 ;) 是的,可移植的方法是转换为指向具有已知大小的类型的指针并对其进行算术运算。如果您不需要可移植性并且您的编译器记录了void * 算术以特定方式工作,您可以使用它。但当然,在某些时候你将不得不移植到不同的编译器......
【解决方案2】:

接受的答案是一个很好的总结,我想更清楚地说明为什么要使用一个或另一个。 ;)

虽然 (void *) 和 (char *) 都可以等效地转换为任何其他指针类型,只有在 (char *) 和 (void *) 上执行指针运算才合法,如果你希望遵守标准 C。

为什么两者都用作指针?大多数与 (void *) 的指针转换都可以在没有强制转换的情况下完成,但 (char *) 的使用是对过去的回忆。

GCC 不会就 (void *) 上的指针运算发出警告,因为它不是一个旨在与标准 C 兼容而是为 GNU C 兼容的编译器。要符合标准 C,您可以使用以下标志:

gcc -ansi -pedantic -Wall -Wextra -Werror <more args...>

我的底线:

  • 如果您想执行指针运算:使用 (char *)
  • 如果您希望获取指针地址以便稍后将其转换为另一种类型:使用 (void *)

【讨论】:

    猜你喜欢
    • 2017-02-14
    • 1970-01-01
    • 2018-06-10
    • 2018-04-05
    • 2011-06-30
    • 2019-05-24
    • 1970-01-01
    • 2021-11-26
    • 1970-01-01
    相关资源
    最近更新 更多