Pointer decrementation delivers wrong result

H

Hipo

Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;

std::cout << *reader-- << std::endl;
std::cout << *reader-- << std::endl;
std::cout << *reader-- << std::endl;



The first output and the third output are OK. But the second output
gives me data that doesn't match to any values in the char array.
If I'm doing the same operation from the beginning and incrementing the
pointer all values are read like they should.

I'm really puzzled.

g, Hipo
 
R

Rolf Magnus

Hipo said:
Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;

&temporary is the address of the array. &temporary+20 would be the address
of the 20th element of an array of arrays of 160 char. You probably meant
temporary+20 (without the &).
 
H

Hipo

Rolf said:
Hipo said:
Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;

&temporary is the address of the array. &temporary+20 would be the address
of the 20th element of an array of arrays of 160 char. You probably meant
temporary+20 (without the &).

Sorry, typing error

g, Hipo
 
G

Greg

Rolf said:
Hipo said:
Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;

&temporary is the address of the array. &temporary+20 would be the address
of the 20th element of an array of arrays of 160 char. You probably meant
temporary+20 (without the &).

Eliminating the & in front of the temporary array makes no difference -
the address of the reader variable is the same. And that address works
out to the 21st element of an array of 8 byte integers which in turn is
equivalent to the address of the 161st character of the 160 character
array. In other words, the reader variable starts by pointing to the
first byte beyond the memory allocated for the temporary array.

This code certainly makes a good example why pointers and C arrays are
best avoided.

Greg
 
R

Rolf Magnus

Greg said:
Rolf said:
Hipo said:
Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;

&temporary is the address of the array. &temporary+20 would be the
address of the 20th element of an array of arrays of 160 char. You
probably meant temporary+20 (without the &).

Eliminating the & in front of the temporary array makes no difference -
the address of the reader variable is the same.

Oh. right. The pointer gets converted first, then the addidtion is done. I
was thinking the other way round.
 
B

boaz_sade

Greg said:
Rolf said:
Hipo said:
Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;

&temporary is the address of the array. &temporary+20 would be the address
of the 20th element of an array of arrays of 160 char. You probably meant
temporary+20 (without the &).

Eliminating the & in front of the temporary array makes no difference -
the address of the reader variable is the same. And that address works
out to the 21st element of an array of 8 byte integers which in turn is
equivalent to the address of the 161st character of the 160 character
array. In other words, the reader variable starts by pointing to the
first byte beyond the memory allocated for the temporary array.

This code certainly makes a good example why pointers and C arrays are
best avoided.

Greg
I think that this is an example of how you can violatate and rule about
writing good code. Above all this is not even deterministic on
different compilers. Even better it seems that the write of this code
don't know how should it really works. Last and not least why on earth
would you ever even think about writing this kind of code?
 
T

Tomás

Hipo posted:
Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;


That line behaves identically to:


unsigned __int64 *reader = reinterpret_cast<unsigned __int64 *>(

reinterpret_cast<char *>(temporary) + sizeof(unsigned __int64[20])

);



"reader" now points to the first byte AFTER the last element of
"temporary". Try changing that 20 to 12:


unsigned __int64 *reader = reinterpret_cast<unsigned __int64 *>(

reinterpret_cast<char *>(temporary) + sizeof(unsigned __int64[12])

);

std::cout << *reader-- << std::endl;
std::cout << *reader-- << std::endl;
std::cout << *reader-- << std::endl;


Two caveats:

(1) Beware of trapping bits.
(2) You're deallocating the pointer to one BEFORE the array.


Try the following code:

#include <iostream>
#include <ostream>
#include <cstdlib>

enum { quantity = 20 };

int main()
{
typedef unsigned __int64 uint64;

uint64 big_numbers[quantity] =
{ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,
11,12,13,14,15,16,17,18,19,20 };

unsigned char temporary[160];


/* That would be better written as:

unsigned char temporary[ sizeof(uint64[quantity]) ]; */


std::memcpy(temporary, big_numbers, sizeof( big_numbers ) );


for(uint64 *reader = reinterpret_cast<uint64*>(

reinterpret_cast<char *>(temporary)
+ sizeof(uint64[20])

);

reader-- > reinterpret_cast<uint64*>(temporary);

/* No action */ )
{
std::cout << *reader << '\n';
}


std::system("PAUSE");
}



-Tomás
 
H

Hipo

Greg said:
Rolf said:
Hipo wrote:

Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;
&temporary is the address of the array. &temporary+20 would be the address
of the 20th element of an array of arrays of 160 char. You probably meant
temporary+20 (without the &).
Eliminating the & in front of the temporary array makes no difference -
the address of the reader variable is the same. And that address works
out to the 21st element of an array of 8 byte integers which in turn is
equivalent to the address of the 161st character of the 160 character
array. In other words, the reader variable starts by pointing to the
first byte beyond the memory allocated for the temporary array.

This code certainly makes a good example why pointers and C arrays are
best avoided.

Greg
I think that this is an example of how you can violatate and rule about
writing good code.

Define good code. I need the data that way and therefor work on it that way.
Above all this is not even deterministic on different compilers.

Not desired. One specific compiler on one specific platform.
Even better it seems that the write of this code don't know how should it
really works.

Believe me, I do.
Last and not least why on earth would you ever even think about writing
> this kind of code?

It's the most efficient way of using data in the algorithm I write.

g, hipo
 
H

Hipo

Tomás said:
Hipo posted:
Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;


That line behaves identically to:


unsigned __int64 *reader = reinterpret_cast<unsigned __int64 *>(

reinterpret_cast<char *>(temporary) + sizeof(unsigned __int64[20])

);



"reader" now points to the first byte AFTER the last element of
"temporary". Try changing that 20 to 12:


unsigned __int64 *reader = reinterpret_cast<unsigned __int64 *>(

reinterpret_cast<char *>(temporary) + sizeof(unsigned __int64[12])

);

std::cout << *reader-- << std::endl;
std::cout << *reader-- << std::endl;
std::cout << *reader-- << std::endl;


Two caveats:

(1) Beware of trapping bits.
(2) You're deallocating the pointer to one BEFORE the array.


Try the following code:

#include <iostream>
#include <ostream>
#include <cstdlib>

enum { quantity = 20 };

int main()
{
typedef unsigned __int64 uint64;

uint64 big_numbers[quantity] =
{ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,
11,12,13,14,15,16,17,18,19,20 };

unsigned char temporary[160];


/* That would be better written as:

unsigned char temporary[ sizeof(uint64[quantity]) ]; */


std::memcpy(temporary, big_numbers, sizeof( big_numbers ) );


for(uint64 *reader = reinterpret_cast<uint64*>(

reinterpret_cast<char *>(temporary)
+ sizeof(uint64[20])

);

reader-- > reinterpret_cast<uint64*>(temporary);

/* No action */ )
{
std::cout << *reader << '\n';
}


std::system("PAUSE");
}



-Tomás

Thanks for advice, I'll trying it this way.
g, Hipo
 
J

Joe Van Dyk

Hipo said:
Greg said:
Rolf Magnus wrote:

Hipo wrote:

Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;

&temporary is the address of the array. &temporary+20 would be the
address
of the 20th element of an array of arrays of 160 char. You probably
meant
temporary+20 (without the &).

Eliminating the & in front of the temporary array makes no difference -
the address of the reader variable is the same. And that address works
out to the 21st element of an array of 8 byte integers which in turn is
equivalent to the address of the 161st character of the 160 character
array. In other words, the reader variable starts by pointing to the
first byte beyond the memory allocated for the temporary array.

This code certainly makes a good example why pointers and C arrays are
best avoided.

Greg

I think that this is an example of how you can violatate and rule about
writing good code.


Define good code. I need the data that way and therefor work on it that
way.
Above all this is not even deterministic on different compilers.


Not desired. One specific compiler on one specific platform.
Even better it seems that the write of this code don't know how should
it really works.


Believe me, I do.
Last and not least why on earth would you ever even think about writing
this kind of code?

It's the most efficient way of using data in the algorithm I write.

g, hipo

Are you sure it's the most efficient way of using data? Have you measured?

Joe
 
R

Ron House

Greg said:
Rolf said:
Hipo wrote:

Hi.

I have the following code:

unsigned char temporary[160];
unsigned __int64 *reader = (unsigned __int64*)&temporary+20;

&temporary is the address of the array. &temporary+20 would be the address
of the 20th element of an array of arrays of 160 char. You probably meant
temporary+20 (without the &).


Eliminating the & in front of the temporary array makes no difference -
the address of the reader variable is the same. And that address works
out to the 21st element of an array of 8 byte integers which in turn is
equivalent to the address of the 161st character of the 160 character
array. In other words, the reader variable starts by pointing to the
first byte beyond the memory allocated for the temporary array.

Cast has higher priority than addition, so your expression:

(unsigned __int64*)temporary+20

means "Convert temporary to unsigned __int64*, then index 20 unsigned
__int64's further along." And that is exactly what you tell us happened.
I don't see the error.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top