zoukankan      html  css  js  c++  java
  • Pointer arithmetic for void pointer in C

    http://stackoverflow.com/questions/3523145/pointer-arithmetic-for-void-pointer-in-c

    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?

    shareimprove this question
     
     
        
    possible duplicate of Error Performing Pointer Arithmetic on void * in MSVC – Carl Norum Aug 19 '10 at 21:43
    2  
    The question sounds as though it assumes that the compiler(/run-time) knows what type of object the pointer was set to, and adds its size to the pointer. That is a complete misconception: it only knows the address. – PJTraill May 5 '15 at 21:22
        
    "If a void pointer which points to data of size x is incremented, how does it get to point x bytes ahead?" It doesn't. Why can't people who have such questions test them before asking - y'know, at least to the bare minimum where they check whether it actually compiles, which this doesn't. -1, can't believe this got +100 and -0. – underscore_d Aug 20 at 6:30

    up vote 165 down vote
    +100

    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 allow void* arithmetic for the purposes of compatibility with GCC. Other compilers (such as MSVC) disallow arithmetic on void*, 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:

    6.5.6-2: For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to an object type and the other shall have integer type.

    So, the question here is whether void* is a pointer to an "object type", or equivalently, whether void is an "object type". The definition for "object type" is:

    6.2.5.1: Types are partitioned into object types (types that fully describe objects) , function types (types that describe functions), and incomplete types (types that describe objects but lack information needed to determine their sizes).

    And the standard defines void as:

    6.2.5-19: The void type comprises an empty set of values; it is an incomplete type that cannot be completed.

    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:

    6.2.5-27: A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.

    However,

    The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

    So this means that printf("%s", x) has the same meaning whether x has type char* or void*, but it does not mean that you can do arithmetic on a void*.

    Editor's note: This answer has been edited to reflect the final conclusion.

    shareimprove this answer
     
    6  
    From the C99 standard: (6.5.6.2) For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to an object type and the other shall have integer type. (6.2.5.19) The void type comprises an empty set of values; it is an incomplete type that cannot be completed. I think that makes it clear that void* pointer arithmetic is not allowed. GCC has an extension that allows to do this. – Job Aug 19 '10 at 18:29
    1  
    if you no longer think your answer is useful, you can just delete it. – caf Aug 20 '10 at 1:28
    1  
    This answer was useful even though it proved wrong as it contains conclusive proof that void pointers aren't meant for arithmetic. – Ben Flynn Oct 17 '12 at 21:48
    1  
    This is a good answer, it has the right conclusion and the necessary citations, but people who came to this question came to the wrong conclusion because they didn't read to the bottom of the answer. I've edited this to make it more obvious. – Dietrich Epp May 11 '13 at 2:37
    1  
    what about subtracting one void pointer from another? – Michael Sep 18 '15 at 18:12

    Pointer arithmetic is not allowed on void* pointers.

    shareimprove this answer
     
    11  
    +1 Pointer arithmetic is only defined for pointers to (complete) object types. void is an incomplete type that can never be completed by definition. – schot Aug 19 '10 at 15:33
    1  
    @schot: Exactly. Moreover, pointer arithmetic is only defined on a pointer to an element of an array object and only if the result of the operation would be a pointer to an element in that same array or one past the last element of that array. If those conditions are not met, it is undefined behavior. (From C99 standard 6.5.6.8) – Job Aug 19 '10 at 18:39

    You can't do pointer arithmetic on void * types, for exactly this reason!

    shareimprove this answer
     

    cast it to a char pointer an increment your pointer forward x bytes ahead.

    shareimprove this answer
     
        
    Why bother? Just cast it to the right type - which should always be known - and increment that by 1. Casting to char, incrementing by x, and then reinterpreting the new value as some other type is both pointless and undefined behaviour. – underscore_d Aug 20 at 6:32

    You have to cast it to another type of pointer before doing pointer arithmetic.

    shareimprove this answer
     

    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.

    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.
    
    shareimprove this answer
     

    Compiler knows by type cast. Given a void *x:

    • x+1 adds one byte to x, pointer goes to byte x+1
    • (int*)x+1 adds sizeof(int) bytes, pointer goes to byte x + sizeof(int)
    • (float*)x+1 addres sizeof(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)

    shareimprove this answer
     
        
    Althought the first item is not portable and is against the Galateo of C/C++ True. it is nevertheless C-language-correct False. This is doublethink! Pointer arithmetic on void * is syntactically illegal, should not compile, and produces undefined behaviour if it does. If a careless programmer can make it compile by disabling some warning, that's no excuse. – underscore_d Aug 20 at 6:35
        
    @underscore_d: I think some compilers used to allow it as an extension, since it's a lot more convenient than having to cast to unsigned char* to e.g. add a sizeof value to a pointer. – supercat Aug 23 at 14:42
  • 相关阅读:
    Linux 配置gitee
    Linux C errno出错处理
    Linux C进程时间:墙上时钟时间,用户CPU时间,系统CPU时钟时间
    编译错误: 对‘aio_read’未定义的引用
    Linux 异步IO(AIO)
    Linux getaddrinfo获得本机ip地址为何127.0.1.1?
    Linux 文件截断的几种方式
    如何创建守护进程?
    守护进程, 协同进程, 僵尸进程, 孤儿进程概念理解
    对线程安全, 可重入函数, 异步安全的理解
  • 原文地址:https://www.cnblogs.com/zhoug2020/p/6016648.html
Copyright © 2011-2022 走看看