C中空指针的指针算法

Siv*_*ran 162 c pointers void-pointers pointer-arithmetic

当一个指针到特定类型的(比如int,char,float,..)被递增,其值增加该数据类型的大小.如果void指向大小数据的指针x递增,它如何获得指向x前面的字节?编译器如何知道添加x指针的值?

M. *_* E. 267

最后得出结论:在算法void*非法的C和C++.

GCC允许它作为扩展,参见Arithmetic on void- 和Function-Pointers(请注意,本节是本手册"C Extensions"章节的一部分).Clang和ICC可能允许void*算术以便与GCC兼容.其他编译器(如MSVC)不允许算术开启void*,如果-pedantic-errors指定了标志,或者指定了标志,GCC将禁止它-Werror-pointer-arith(如果您的代码库也必须使用MSVC编译,则此标志很有用).

C标准发言

报价取自n1256草案.

标准对添加操作的描述说明:

6.5.6-2:另外,两个操作数都应具有算术类型,或者一个操作数应为指向对象类型的指针,另一个操作数应为整数类型.

所以,这里的问题是是否void*是指向"对象类型"的指针,或者等效地,是否void是"对象类型"."对象类型"的定义是:

6.2.5.1:类型被划分为对象类型(完全描述对象的类型),函数类型(描述函数的类型)和不完整类型(描述对象但缺少确定其大小所需信息的类型).

标准定义void为:

6.2.5-19:void类型包含一组空值; 它是一种不完整的类型,无法完成.

由于void是不完整的类型,因此它不是对象类型.因此,它不是加法运算的有效操作数.

因此,您无法对void指针执行指针运算.

笔记

最初,人们认为void*算术是允许的,因为C标准的这些部分:

6.2.5-27:指向void的指针应具有 指向字符类型的指针相同的表示和对齐要求.

然而,

相同的表示和对齐 要求意味着可互换性作为函数的参数,函数的返回值和联合的成员.

所以这意味着printf("%s", x)具有相同的含义是否x具有类型char*void*,但并不意味着您可以对a进行算术运算void*.

编者注:本答案已经过编辑,以反映最终结论.

  • 从C99标准:(6.5.6.2)*对于另外,任一两个操作数应具有算术类型,或一个操作数应的指针的对象类型和其他应具有整型*(6.2.5.19)*空隙type包含一组空值; 它是一个无法完成的不完整类型.*我认为这表明不允许使用`void*`指针算法.GCC有[扩展](http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Pointer-Arith.html#Pointer-Arith)允许这样做. (7认同)
  • 哦,但是对于指针加法,现在“一个操作数应该是一个指向完整对象类型的指针,另一个应该是整数类型。”。所以我猜用 void* 指针添加指针仍然是未定义的行为。 (2认同)

Job*_*Job 57

指针上不允许指针运算void*.

  • +1指针算法仅为指向(完整)*对象类型*的指针定义.`void`是一个*不完整的类型*,根据定义永远无法完成. (14认同)

Ult*_*ent 16

将它转换为char指针,将指针向前转x字节.

  • 如果您正在编写sort函数,根据`man 3 qsort`应该有`void qsort(void*base,size_t nmemb,size_t size,[snip])`,那么你无法知道"正确的类型" " (7认同)
  • 何必?只需将其强制转换为正确的类型(应该始终知道),然后将其递增1。强制转换为“ char”,递增“ x”,然后将新值重新解释为其他类型既无意义又不确定。 (3认同)

Oli*_*rth 14

你不能对void *类型做指针算术,正是因为这个原因!


msc*_*msc 12

C标准不允许指针运算.然而,GNU C是考虑大小的允许无效1.

C11标准§6.2.5

第 - 19段

void类型包含一组空值; 它是一个不完整的对象类型,无法完成.

以下程序在GCC编译器中正常工作.

#include<stdio.h>

int main()
{
    int arr[2] = {1, 2};
    void *ptr = &arr;
    ptr = ptr + sizeof(int);
    printf("%d\n", *(int *)ptr);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

可能是其他编译器生成错误.


Jak*_*kob 8

在进行指针运算之前,必须将其强制转换为其他类型的指针.


小智 5

空指针可以指向任何内存块。因此,当我们尝试对void指针进行指针算术运算时,编译器不知道要增加/减少多少字节。因此,空指针必须先被类型转换为已知类型,然后才能参与任何指针算术。

void *p = malloc(sizeof(char)*10);
p++; //compiler does how many where to pint the pointer after this increment operation

char * c = (char *)p;
c++;  // compiler will increment the c by 1, since size of char is 1 byte.
Run Code Online (Sandbox Code Playgroud)