C中void指针的指针运算
当指向特定类型(例如 int
、char
、float
等)的指针递增时,其值会增加该数据类型。如果指向大小为 x 的数据的 void 指针递增,它如何指向前面 x 字节?编译器如何知道将 x 添加到指针的值中?
When a pointer to a particular type (say int
, char
, float
, ..) is incremented, its value is increased by the size of that data type. If a void
pointer which points to data of size x
is incremented, how does it get to point x
bytes ahead? How does the compiler know to add x
to value of the pointer?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
最终结论:
void*
上的算术在 C 和 C++ 中都是非法的。GCC 允许将其作为扩展,请参阅 Arithmetic on
void
-和函数指针(请注意,本节是手册“C 扩展”一章的一部分)。 Clang 和 ICC 可能允许void*
算术,以便与 GCC 兼容。其他编译器(例如 MSVC)不允许对void*
进行算术,如果指定了-pedantic-errors
标志,或者如果-Werror=指定了pointer-arith
标志(如果您的代码库还必须使用MSVC 进行编译,则该标志很有用)。C Standard Speaks
引述取自 n1256 草案。
标准对加法运算的描述如下:
因此,这里的问题是
void*
是否是指向“对象类型”的指针,或者同等地,void
是否是“对象类型”。 “对象类型”的定义是:标准将
void
定义为:由于
void
是不完整类型,因此它不是对象类型。因此它不是加法运算的有效操作数。因此,您无法对
void
指针执行指针算术。注释
最初,由于 C 标准的以下部分,人们认为
void*
算术是允许的:然而,
因此,这意味着无论
x
的类型为char*
还是void*,
,但这并不意味着您可以对printf("%s", x)
都具有相同的含义void*
进行算术运算。Final conclusion: arithmetic on a
void*
is illegal in both C and C++.GCC allows it as an extension, see Arithmetic on
void
- and Function-Pointers (note that this section is part of the "C Extensions" chapter of the manual). Clang and ICC likely allowvoid*
arithmetic for the purposes of compatibility with GCC. Other compilers (such as MSVC) disallow arithmetic onvoid*
, and GCC disallows it if the-pedantic-errors
flag is specified, or if the-Werror=pointer-arith
flag is specified (this flag is useful if your code base must also compile with MSVC).The C Standard Speaks
Quotes are taken from the n1256 draft.
The standard's description of the addition operation states:
So, the question here is whether
void*
is a pointer to an "object type", or equivalently, whethervoid
is an "object type". The definition for "object type" is:And the standard defines
void
as:Since
void
is an incomplete type, it is not an object type. Therefore it is not a valid operand to an addition operation.Therefore you cannot perform pointer arithmetic on a
void
pointer.Notes
Originally, it was thought that
void*
arithmetic was permitted, because of these sections of the C standard:However,
So this means that
printf("%s", x)
has the same meaning whetherx
has typechar*
orvoid*
, but it does not mean that you can do arithmetic on avoid*
.void*
指针不允许进行指针算术。Pointer arithmetic is not allowed on
void*
pointers.将其转换为 char 指针,并将指针向前增加 x 个字节。
cast it to a char pointer an increment your pointer forward x bytes ahead.
C 标准不允许void指针算术。然而,考虑到 void 的大小为
1
,GNU C 是允许的。C11 标准§6.2.5
第 19 段
以下程序在 GCC 编译器中运行良好。
可能是其他编译器产生错误。
The C standard does not allow void pointer arithmetic. However, GNU C is allowed by considering the size of void is
1
.C11 standard §6.2.5
Paragraph - 19
Following program is working fine in GCC compiler.
May be other compilers generate an error.
正是由于这个原因,您不能对
void *
类型进行指针算术!You can't do pointer arithmetic on
void *
types, for exactly this reason!空指针可以指向任何内存块。因此,当我们尝试对 void 指针进行指针算术时,编译器不知道要增加/减少多少字节。因此,void 指针必须首先被类型转换为已知类型,然后才能参与任何指针算术。
Void pointers can point to any memory chunk. Hence the compiler does not know how many bytes to increment/decrement when we attempt pointer arithmetic on a void pointer. Therefore void pointers must be first typecast to a known type before they can be involved in any pointer arithmetic.
在进行指针算术之前,您必须将其转换为另一种类型的指针。
You have to cast it to another type of pointer before doing pointer arithmetic.
[答案复制自 评论 ://stackoverflow.com/questions/73996340">稍后,重复的问题]
允许对空指针进行算术是一个有争议的非标准扩展。如果你用汇编语言思考,其中指针只是地址,那么对 void 指针进行算术是有意义的,加 1 只是加 1。但是如果你用 C 术语思考,使用 C 的指针算术模型,对任意值加 1指针
p
实际上将sizeof(*p)
添加到地址,这就是您希望指针算术执行的操作,但是由于sizeof(void)
> 为 0,它会分解为 void 指针。如果您用 C 术语思考,您不介意它崩溃,并且您不介意将显式转换插入
(char *)
(如果这是您想要的算术)。但是,如果您在汇编程序中思考,您希望它能够正常工作,这就是为什么扩展(尽管偏离了 C 中指针算术的正确定义)在某些圈子中是可取的,并且由某些编译器提供。[answer copied from a comment on a later, duplicate question]
Allowing arithmetic on void pointers is a controversial, nonstandard extension. If you're thinking in assembly language, where pointers are just addresses, arithmetic on void pointers makes sense, and adding 1 just adds 1. But if you're thinking in C terms, using C's model of pointer arithmetic, adding 1 to any pointer
p
actually addssizeof(*p)
to the address, and this is what you want pointer arithmetic to do, but sincesizeof(void)
is 0, it breaks down for void pointers.If you're thinking in C terms you don't mind that it breaks down, and you don't mind inserting explicit casts to
(char *)
if that's the arithmetic you want. But if you're thinking in assembler you want it to just work, which is why the extension (though a departure from the proper definition of pointer arithmetic in C) is desirable in some circles, and provided by some compilers.void 指针中不允许进行指针算术。
原因:指针算术与普通算术不同,因为它是相对于基地址发生的 >。
解决方案:在算术运算时使用类型转换运算符,这将使执行指针算术的表达式知道基本数据类型。
ex: point 是 void 指针
Pointer arithmetic is not allowed in the void pointer.
Reason: Pointer arithmetic is not the same as normal arithmetic, as it happens relative to the base address.
Solution: Use the type cast operator at the time of the arithmetic, this will make the base data type known for the expression doing the pointer arithmetic.
ex: point is the void pointer
编译器通过类型转换知道。给定一个
void *x
:x+1
将一个字节添加到x
,指针指向字节x+1
(int*)x+1
添加sizeof(int)
字节,指针指向字节x + sizeof(int)
(float *)x+1
addressizeof(float)
字节,虽然
第一项不可移植并且与 C/C++ 的 Galateo 相悖,但它仍然是 C 语言正确的,这意味着它将在大多数编译器上编译为某些内容,可能需要适当的标志(例如 -Wpointer-arith)
Compiler knows by type cast. Given a
void *x
:x+1
adds one byte tox
, pointer goes to bytex+1
(int*)x+1
addssizeof(int)
bytes, pointer goes to bytex + sizeof(int)
(float*)x+1
addressizeof(float)
bytes,etc.
Althought the first item is not portable and is against the Galateo of C/C++, it is nevertheless C-language-correct, meaning it will compile to something on most compilers possibly necessitating an appropriate flag (like -Wpointer-arith)