Can a pointer (address) ever be negative?

前端 未结 13 1571
情书的邮戳
情书的邮戳 2020-11-29 05:53

I have a function that I would like to be able to return special values for failure and uninitialized (it returns a pointer on success).

Currently i

相关标签:
13条回答
  • 2020-11-29 06:19

    Actually, (at least on x86), the NULL-pointer exception is generated not only by dereferencing the NULL pointer, but by a larger range of addresses (eg, first 65kb). This helps catching such errors as

    int* x = NULL;
    x[10] = 1;
    

    So, there are more addresses that are garanteed to generate the NULL pointer exception when dereferenced. Now consider this code (made compilable for AndreyT):

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    #define ERR_NOT_ENOUGH_MEM (int)NULL
    #define ERR_NEGATIVE       (int)NULL + 1
    #define ERR_NOT_DIGIT      (int)NULL + 2
    
    char* fn(int i){
        if (i < 0)
            return (char*)ERR_NEGATIVE;
        if (i >= 10)
            return (char*)ERR_NOT_DIGIT;
        char* rez = (char*)malloc(strlen("Hello World ")+sizeof(char)*2);
        if (rez)
            sprintf(rez, "Hello World %d", i);
        return rez;
    };
    
    int main(){
        char* rez = fn(3);
        switch((int)rez){
            case ERR_NOT_ENOUGH_MEM:    printf("Not enough memory!\n"); break;
            case ERR_NEGATIVE:          printf("The parameter was negative\n"); break;
            case ERR_NOT_DIGIT:         printf("The parameter is not a digit\n"); break;
            default:                    printf("we received %s\n", rez);
        };
        return 0;
    };
    

    this could be useful in some cases. It won't work on some Harvard architectures, but will work on von Neumann ones.

    0 讨论(0)
  • 2020-11-29 06:20

    The C language does not define the notion of "negativity" for pointers. The property of "being negative" is a chiefly arithmetical one, not in any way applicable to values of pointer type.

    If you have a pointer-returning function, then you cannot meaningfully return the value of -1 from that function. In C language integral values (other than zero) are not implicitly convertible to pointer types. An attempt to return -1 from a pointer-returning function is an immediate constraint violation that will result in diagnostic message. In short, it is an error. If your compiler allows it, it simply means that it doesn't enforce that constraint too strictly (most of the time they do it for compatibility with pre-standard code).

    If you force the value of -1 to pointer type by an explicit cast, the result of the cast will be implementation-defined. The language itself makes no guarantees about it. It might easily prove to be the same as some other, valid pointer value.

    If you want to create a reserved pointer value, there no need to malloc anything. You can simple declare a global variable of the desired type and use its address as the reserved value. It is guaranteed to be unique.

    0 讨论(0)
  • 2020-11-29 06:21

    @James is correct, of course, but I'd like to add that pointers don't always represent absolute memory addresses, which theoretically would always be positive. Pointers also represent relative addresses to some point in memory, often a stack or frame pointer, and those can be both positive and negative.

    So your best bet is to have your function accept a pointer to a pointer as a parameter and fill that pointer with a valid pointer value on success while returning a result code from the actual function.

    0 讨论(0)
  • 2020-11-29 06:23

    James answer is probably correct, but of course describes an implementation choice, not a choice that you can make.

    Personally, I think addresses are "intuitively" unsigned. Finding a pointer that compares as less-than a null pointer would seem wrong. But ~0 and -1, for the same integer type, give the same value. If it's intuitively unsigned, ~0 may make a more intuitive special-case value - I use it for error-case unsigned ints quite a lot. It's not really different (zero is an int by default, so ~0 is -1 until you cast it) but it looks different.

    Pointers on 32-bit systems can use all 32 bits BTW, though -1 or ~0 is an extremely unlikely pointer to occur for a genuine allocation in practice. There are also platform-specific rules - for example on 32-bit Windows, a process can only have a 2GB address space, and there's a lot of code around that encodes some kind of flag into the top bit of a pointer (e.g. for balancing flags in balanced binary trees).

    0 讨论(0)
  • 2020-11-29 06:32

    What's the difference between failure and unitialized. If unitialized is not another kind of failure, then you probably want to redesign the interface to separate these two conditions.

    Probably the best way to do this is to return the result through a parameter, so the return value only indicates an error. For example where you would write:

    void* func();
    
    void* result=func();
    if (result==0)
      /* handle error */
    else if (result==-1)
      /* unitialized */
    else
      /* initialized */
    

    Change this to

    // sets the *a to the returned object
    // *a will be null if the object has not been initialized
    // returns true on success, false otherwise
    int func(void** a);
    
    void* result;
    if (func(&result)){
      /* handle error */
      return;
    }
    
    /*do real stuff now*/
    if (!result){
      /* initialize */
    }
    /* continue using the result now that it's been initialized */
    
    0 讨论(0)
  • 2020-11-29 06:32

    Positive or negative is not a meaningful facet of pointer type. They pertain to signed integer including signed char, short, int etc.

    People talk about negative pointer mostly in a situation that treats pointer's machine representation as an integer type. e.g. reinterpret_cast<intptr_t>(ptr). In this case, they are actually talking about the cast integer, not the pointer itself.

    In some scenario I think pointer is inherently unsigned, we talk about address in terms below or above. 0xFFFF.FFFF is above 0x0AAAA.0000, which is intuitively for human beings. Although 0xFFFF.FFFF is actually a "negative" while 0x0AAA.0000 is positive.

    But in other scenarios such as pointer subtraction (ptr1 - ptr2) that results in a signed value whose type is ptrdiff_t, it's inconsistent when you compare with integer's subtraction, signed_int_a - signed_int_b results in a signed int type, unsigned_int_a - unsigned_int_b produces an unsigned type. But for pointer subtraction, it produces a signed type, because the semantic is the distance between two pointers, the unit is number of elements.

    In summary I suggest treating pointer type as standalone type, every type has it's set of operation on it. For pointers (excluding function pointer, member function pointer, and void *):

    1. List item
    2. +, +=

      ptr + any_integer_type

    3. -, -=

      ptr - any_integer_type

      ptr1 - ptr2

    4. ++ both prefix and postfix

    5. -- both prefix and postfix

    Note there are no / * % operations for pointer. That's also supported that pointer should be treated as a standalone type, instead of "A type similar to int" or "A type whose underlying type is int so it should looks like int".

    0 讨论(0)
提交回复
热议问题