Question:
In C, is using negative of a pointer in a "if" or similar statement semantically correct?
electric
2012-09-29 07:09:53 UTC
Here's a segment of an Algorithm for Post-order Traversal of binary trees taken from my book:

--------------------------------
If right[node]!=NULL
[right child exists]
Set top=top+1,stack[top]=-(right[node])
[Pushes the negative pointer]
[End of If structure]
-----------------------------------

Later there is a segment that compares if the value popped from the stack is a non-negative or a negative pointer.So what I mean is, can we assign the negative of a pointer as an array element as in "stack[top]=-(right [node]) above?Is it OK?Pointer after all is an unsigned integer value(address) and I don't see anything wrong with using it's negative.Of course for a pointer "ptr", I know something like "*(-ptr)" is totally absurd.But can we use something like "int a=-ptr"?
Four answers:
Jonathan
2012-09-29 13:18:19 UTC
A compiler should probably give you an error if you are applying the unary negation operator to a pointer. So far as I'm aware, that operator requires a number of some kind, not a pointer.



From the 1999 C Standard:

    6.5.3.3 Unary arithmetic operators

    Constraints

        The operand of the unary + or - operator shall have arithmetic type;

        of the ~ operator, integer type; of the ! operator, scalar type.

    Semantics

        The result of the unary + operator is the value of its (promoted)

        operand. The integer promotions are performed on the operand,

        and the result has the promoted type.

        The result of the unary - operator is the negative of its (promoted)

        operand. The integer promotions are performed on the operand,

        and the result has the promoted type.



I don't believe there is a valid "integer promotion" for pointers (except in the unusual, but specified, case of the NULL pointer which the standard requires to be able to be promoted to an integer.)



If there were such a valid integer promotion before performing the unary minus operator, then the result would anyway be an integer and not a pointer. So again, there should be an error turning that back into a pointer, again.



But there isn't such a promotion, so it doesn't matter. The point is, either way, there should be an error.



It is valid to take the difference between pointers of the same type. This computes the number of items between the two pointers and produces an integer value. So it WOULD be valid to take the difference, like this:



    int array[20];

    int *p= &array[5];

    int diff= ((char *) 0) - (char *) p;



This first creates a NULL character pointer constant of 0 and then converts the integer pointer to a character pointer as well, before taking the difference. So the result would be a negative value. It amounts to something similar, you could argue. And it is legal, I believe.



However, to reverse this back into a valid pointer would require something like the following:



    int *q= (int *) (((char *) 0) + diff);



It's all pretty ugly. Besides, it's probably not guaranteed to have defined behavior. The size of pointers to various types of objects are not guaranteed to be the same size. Only the (void *) pointer is guaranteed to be large enough to hold ANY data pointer (not function pointer, even.) And you cannot do computations with a void pointer. It must first be converted.



Negation is, in effect, the same thing as adding a large constant defined by the word size and the numerical notation form that is used. If you think about that, in terms of pointers, this just "assumes" that memory pointers with some large offset to them can be safely compared with pointers without that added offset. But even that isn't entirely safe to do. So far as I'm aware, there is no such guarantee in C like that. Only the NULL pointer has specific guarantees like that.



So it's not safe and it's likely to generate errors.



I do NOT agree with fallible (or anyone else) that pointers are unsigned ints. On some machines I've experienced, they are VERY SPECIAL values and the very hardware they run on cannot represent them as integers of any kind. Integers in C are usually of a size and type that matches up with the arithmetic logic unit's data size. Pointers can be not only MUCH LARGER but also MUCH MORE COMPLEX. For example, on the 8088, a pointer was two 16-bit values which are added in the hardware with one multiplied by 16 before being added to the other in order to create a 20 bit physical address. The ALU handled 16 bit values. Internally, though, the C compiler usually (not always, because Borland did it differently than Microsoft for some years) handled a pointer as a pairing of two 16-bit values. Worse, there were many different pair-values that would point to the exact same 20 bit physical address, despite being very different pairs of 16 bit values.



If you need storage of different kinds of pointers into the same variable, then you are supposed to use (void *) as the type and convert back and forth.



As mentioned, it is POSSIBLE to negate a pointer by first converting it to a "span" (which is perfectly legal and portable) and then negating that difference (also legal.) This difference can then (legally and portably) be converted back into a pointer by adding it to a pointer that points at the base of an array in memory, for example. This is all within the standard. But simple negation of a pointer is not.



Oh, and you SHOULD have included a declaration/definition of your stack variable.



A very simple depth-first, post-order traversal of a tree is nothing more than this in C:



void treewalk( node * n, void (*p)( node * ) ) {

        if ( n != NULL ) {

            treewalk( n->left );

            treewalk( n->right );

            p( n );

        }

}
fallibledragon
2012-09-29 14:26:44 UTC
You can subtract them, IF you know that one is higher than the other, AND you do not care about platform independent code. However, you almost certainly should care about platform independence, especially if you're asking questions like this. There's almost no legitimate reason to be using pointer arithmetic these days, outside some VERY specialised memory management classes, if using a language like C++ rather than C.



But, you cannot just take the negative of a pointer and get some sort of generally useful answer, because, as you say, they are unsigned on most platforms. If there's any platform where a pointer isn't an unsigned integer (as opposed to an unsigned int) at the hardware level, then it's probably strictly an address, and not interchangeable with integers at all.



To clarify, unsigned ints and signed ints hold the same total number of bits, except that in signed ints, one bit is used for the sign. So, if you take a unsigned number, convert it to signed, and use the sign bit to represent something other than the same value as before (i.e., if you modify the value by making it negative, and don't just convert it back to unsigned again), then you're DISCARDING INFORMATION about the ACTUAL address of the pointer. Also, when you convert an unsigned number to signed, it will often become negative automatically, so about half of your numbers could become negative even if you DON'T make them negative explicitly.
roger
2012-09-29 15:00:18 UTC
No. You cannot take the negative of a pointer. That does not make sense.

A pointer holds an address. Taking the negative of an address does not make sense.

If your house address was 123 main street (-123 main street) does not have any meaning.

You can subtract two pointers to get the number of elements between them. Adding then does not make sense.

You can think of pointers as mileage markers on a highway. Taking the difference between two of them will give you the mileage between them. Adding them has no meaning. Making one of them negative does not mean anything. And the two mileage markers have to be on the same highway.

Taking the difference of markers on different highways will not tell you anything,
Sarbada
2012-09-29 14:23:51 UTC
Hi,



I am C developer having 11 years of experience in coding, i have made video tutorials are free to download, i request you to have a look at them, please share or like if useful.



http://www.youtube.com/watch?v=L7q7aRe6c98


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...