Operating System - OpenVMS
1752686 Members
5539 Online
108789 Solutions
New Discussion юеВ

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

 
SOLVED
Go to solution
Jingwei
Occasional Contributor

Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

Recently, we have a question, the codes is below:
(openvms v8.3, HP C v7.2, it happans both on I64 and AXP)

/***** begin of codes ******/
#include "stdio.h"
#include "far_pointers.h"

#pragma required_pointer_size save
#pragma required_pointer_size 64

typedef unsigned char* UCHAR_PQ;

#pragma required_pointer_size restore


int main()
{
UCHAR_PQ foundKey;
UCHAR_PQ x;
unsigned __int64 y;
foundKey = 4599194146;
x = (unsigned __int64)1L;
y = 1;
printf("UCHAR_PQ x=%lld\n", x);
printf("unsigned __int64 y=%lld\n", y);
unsigned long recPos;
printf("UCHAR_PQ foundKey:%lld\n", (UCHAR_PQ)foundKey);
printf("foundKey-1:%lld\n", (unsigned __int64)(foundKey-1));

/***** the line is the question *****/
printf("foundKey-x:%lld\n", (unsigned __int64)(foundKey-x));
/***** *****/

printf("foundKey-y:%lld\n", (unsigned __int64)(foundKey-y));
printf("foundKey-(unsigned __int64)x:%lld\n", (unsigned __int64)(foundKey-(unsigned __int64)x));
printf("unsigned int64:%lld\n", (unsigned __int64)((unsigned __int64)foundKey-(unsigned __int64)x));
printf("UCHAR_PQ size:%d\n", sizeof(UCHAR_PQ));

return 0;
}
/***** end of codes *****/

compile, link and run it
(there r some warning during compiling, but I think it can be ignored)

the result is

UCHAR_PQ x=1
unsigned __int64 y=1
UCHAR_PQ foundKey:4599194146
foundKey-1:4599194145
foundKey-x:304226849
foundKey-y:4599194145
foundKey-(unsigned __int64)x:4599194145
unsigned int64:4599194145
UCHAR_PQ size:8
recPos = 9507089

our question is :

Why foundKey-x = 304226849, it should be 4599194145, I think

we find:
304226849 = 0x12222221
4599194145 = 0x112222221

that means :
64-bit pointer MINUS 64-bit pointer is 32-bit integer

It is right or not?

Please help me, thanks.
9 REPLIES 9
Steven Schweda
Honored Contributor

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

> (there r some warning during compiling, but
> I think it can be ignored)

foundKey = (UCHAR_PQ) 4599194146;
x = (UCHAR_PQ) 1;

No complaints, same results.

To _me_ it looks like a compiler bug, but
there could be some part of the C standard
for pointer arithmetic which I don't
understand. It seems to do well enough with
8-byte integers.

alp $ cc /version
HP C V7.3-009 on OpenVMS Alpha V7.3-2
Jingwei
Occasional Contributor

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

Hi, Steven Schweda

Thank you for your reply

I also think it may be a bug.
Jingwei
Occasional Contributor

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

>alp $ cc /version
>HP C V7.3-009 on OpenVMS Alpha V7.3-2

It means you had tested it in HP C V7.3, doesn't it?

If yes, then thank you again, I just planed to find the newest compiler and test it :)
Hoff
Honored Contributor

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

Ah, C, my old friend. Moving stuff between different-sized variables and signed and unsigned variables can have some very unexpected results; variable promotion and demotion is an obscure corner of C.

http://h71000.www7.hp.com/commercial/c/docs/6180profile_018.html#index_x_663

Here's a local test run with some updated and tweaked code...

$ cc /version
HP C V7.3-009 on OpenVMS Alpha V7.3-2
$ cc x/pointer=long
$ link x
$ r x
UCHAR_PQ x=1
unsigned __int64 y=1
UCHAR_PQ foundKey:4599194146
foundKey-1:4599194145
foundKey-x:4599194145
foundKey-y:4599194145
foundKey-(unsigned long long)x:4599194145
unsigned int64:4599194145
UCHAR_PQ size:8
$

Bugfixes and corrections below:

#include
#include
#include

#pragma required_pointer_size save
#pragma required_pointer_size 64

typedef unsigned char* UCHAR_PQ;

#pragma required_pointer_size restore


int main()
{
UCHAR_PQ foundKey;
UCHAR_PQ x;
unsigned long long y;
foundKey = (void *) 4599194146UL;
x = (UCHAR_PQ) (unsigned long long *)1UL;
y = 1;
printf("UCHAR_PQ x=%lld\n", x);
printf("unsigned __int64 y=%lld\n", y);
unsigned long recPos;
printf("UCHAR_PQ foundKey:%lld\n", (UCHAR_PQ)foundKey);
printf("foundKey-1:%lld\n", (unsigned long long)(foundKey-1));

/***** the line is the question *****/
printf("foundKey-x:%lld\n", (unsigned long long)(foundKey-(unsigned long long) x));
/***** *****/

printf("foundKey-y:%lld\n", (unsigned long long)(foundKey-y));
printf("foundKey-(unsigned long long)x:%lld\n", (unsigned long long)(foundKey-(unsigned long long)x));
printf("unsigned int64:%lld\n", (unsigned __int64)((unsigned long long)foundKey-(unsigned long long)x));
printf("UCHAR_PQ size:%d\n", sizeof(UCHAR_PQ));

return EXIT_SUCCESS;
}
Hein van den Heuvel
Honored Contributor
Solution

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

This surprised me as well.
The test programs is nice an comprehensive, and shows the workaround. Thanks. What I tend to do to figure out these problems without actually running code is to
$CC/NOOPT/LIST/MACHINE.
To wit:

original:
printf ... (unsigned __int64)(foundKey-x));

SUBQ foundKey, x, R0
SEXTL R0, R17

Workaround:
printf ... (unsigned __int64) foundKey - (unsigned __int64) x );

SUBQ foundKey, x, R17

This workaround is hinted to be the DEC C User Guide: "1.7.5 Avoiding Problems"
" ├в ┬в Do bit manipulation on unsigned int and unsigned _ _int64, and carefully
cast pointers to and from them.
"

The origin of the trouble is probably best described in :

The DEC-C language reference manual gives a hint in "6.5.2 Additive Operators:
"When two pointers to elements of the same array are subtracted, the result
(calculated by dividing the difference between the two addresses by the length
of one element) is of type ptrdiff_t, which in HP C is int, and represents
the number of elements between the two addressed elements. If the two
elements are not in the same array, the result of this operation is undefined."

So it seems pointer aritmetic is only valid within the same, 32 bit, array space.

Also see:

Referenence manual:
"B.23 Additive Operators (├В┬з3.3.6)
Pointers to members of the same array can be subtracted. The result is the
number of elements between the two array members. The type of the result is
ptrdiff_t. HP C defines this type as int."

And see: stddef.h

fwiw,
Hein.




Steven Schweda
Honored Contributor

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

> It means you had tested it in HP C V7.3,
> doesn't it?

Yes. V7.3-009.

> [...] B.23 Additive Operators [...]

As I said, "[...] there could be [...]".
Everything's complicated.

You can usually find an up-to-date compiler
on a TestDrive system, too, although the
Alphas are gone now:

http://www.testdrive.hp.com/
Dennis Handly
Acclaimed Contributor

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

>Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

Yes, I've heard that can be the case and someone pointed to Alpha. The Standard says the result of a pointer difference is a ptrdiff_t. In C99 a pointer fits in an intptr_t.

On HP-UX, a ptrdiff_t is a long, either 32 (ILP32) or 64 bit (LP64).

>Hein: So it seems pointer arithmetic is only valid within the same, 32 bit, array space.

Yes, the Standard says it is only valid in the same array. It seems that Tru64/OVMS never did its huge data roll like we did on HP-UX, where everything can be 64 bit. (With still some limitations on locals and parms.)
Jingwei
Occasional Contributor

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

Hi, All

Thank you very much.

I should read the books more carefully :)

So, thank Hein again :)


Eh... it should not be called a "bug". But I hope it can be "fixed" :)

David Jones_21
Trusted Contributor

Re: Is it right that 64-bit pointer MINUS 64-bit pointer IS 32-bit integer

My Plauger/Brodie ANSI C reference says subtraction of pointers is only valid if both pointer's values are addresses of elements of the same array (or 1 element past the last) and the result is of type ptrdiff_t (a signed integer type defined in stddef.h).
I'm looking for marbles all day long.