473,320 Members | 1,831 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Endian Reversal?

What is the fastest way to convert __int64 type from BigEndian To Little
Endian?
I wrote this function:
---
uint64 EndianReverse(uint64 number) {
typedef unsigned __int8 uint8;
const int size = sizeof(uint64);
uint8 polje[size] = {0};
uint8 *ptr = reinterpret_cast<uint8*>(&number);
int index = 0;
for (int i=size-1 ; i>=0 ; i--) {
polje[index] = *(ptr+i);
index++;
}
uint64 *retPtr = reinterpret_cast<uint64*>(polje);
return *retPtr;
}
---

but i know there is faster way with logical and shift opertors, so if anyone
knows it i would be appreciated.
Mar 16 '06 #1
11 4111
Tosha wrote:
What is the fastest way to convert __int64 type from BigEndian To Little
Endian?
I wrote this function:
---
uint64 EndianReverse(uint64 number) {
typedef unsigned __int8 uint8;
const int size = sizeof(uint64);
uint8 polje[size] = {0};
uint8 *ptr = reinterpret_cast<uint8*>(&number);
int index = 0;
for (int i=size-1 ; i>=0 ; i--) {
polje[index] = *(ptr+i);
index++;
}
uint64 *retPtr = reinterpret_cast<uint64*>(polje);
return *retPtr;
}
---

but i know there is faster way with logical and shift opertors, so if anyone
knows it i would be appreciated.


The "fastness" has to be _measured_, not deduced from the types of
operations used. That said, I'd expect this to be a bit faster:

template<class T> T EndianReverse(T t)
{
unsigned char uc[sizeof t];
memcpy(uc, &t, sizeof t);
for (unsigned char *b = uc, *e = uc + sizeof(T) - 1; b < e; ++b, --e)
std::swap(*b, *e);
memcpy(&t, uc, sizeof t);
return t;
}

.... and it is (just measured), by about 20%, on my machine.

V
--
Please remove capital As from my address when replying by mail
Mar 16 '06 #2
Me
Tosha wrote:
What is the fastest way to convert __int64 type from BigEndian To Little
Endian?

<snip code>

Since it looks like you're on visual studio, how about trying the
_byteswap_uint64 intrinsic:

http://msdn2.microsoft.com/en-us/lib...77(VS.80).aspx

Mar 17 '06 #3

"Me" <an*****************@yahoo.com> wrote in message
news:11**********************@p10g2000cwp.googlegr oups.com...
Tosha wrote:
What is the fastest way to convert __int64 type from BigEndian To Little
Endian?

<snip code>

Since it looks like you're on visual studio, how about trying the
_byteswap_uint64 intrinsic:

http://msdn2.microsoft.com/en-us/lib...77(VS.80).aspx


Thank you very much.
Mar 17 '06 #4
Victor Bazarov wrote:
Tosha wrote:
What is the fastest way to convert __int64 type from BigEndian To Little
Endian?
The "fastness" has to be _measured_, not deduced from the types of
operations used. That said, I'd expect this to be a bit faster:

template<class T> T EndianReverse(T t)
{
unsigned char uc[sizeof t];
memcpy(uc, &t, sizeof t);
for (unsigned char *b = uc, *e = uc + sizeof(T) - 1; b < e; ++b, --e)
std::swap(*b, *e);
memcpy(&t, uc, sizeof t);
return t;
}


Why not do it inplace?

template<class T> void InplaceEndianReverse(T& t)
{
unsigned char* tp = reinterpret_cast<unsigned char *>(&t);
for (unsigned char *b = tp, *e = tp + sizeof(T) - 1; b < e; ++b, --e)
std::swap(*b, *e);
return;
}

Or saving at least one of the memcpy's in the out of place syntax?

template<class T> T EndianReverse(T t)
{
T result=t; // "hides" a memcpy.
unsigned char* tp = reinterpret_cast<unsigned char *>(&result);
for (unsigned char *b = tp, *e = tp + sizeof(T) - 1; b < e; ++b, --e)
std::swap(*b, *e);
return result;
}

Shouldn't this make a difference, especially if it is inlined?

Fabio



Mar 18 '06 #5
Fabio Fracassi wrote:
Victor Bazarov wrote:
Tosha wrote:
What is the fastest way to convert __int64 type from BigEndian To
Little Endian?
The "fastness" has to be _measured_, not deduced from the types of
operations used. That said, I'd expect this to be a bit faster:

template<class T> T EndianReverse(T t)
{
unsigned char uc[sizeof t];
memcpy(uc, &t, sizeof t);
for (unsigned char *b = uc, *e = uc + sizeof(T) - 1; b < e;
++b, --e) std::swap(*b, *e);
memcpy(&t, uc, sizeof t);
return t;
}


Why not do it inplace?


Because the behaviour in _your_ case is undefined. You're *not*
allowed to use the pointer obtained from 'reiterpret_cast' for
anything _except_ converting back to what it was.
template<class T> void InplaceEndianReverse(T& t)
{
unsigned char* tp = reinterpret_cast<unsigned char *>(&t);
for (unsigned char *b = tp, *e = tp + sizeof(T) - 1; b < e; ++b,
--e) std::swap(*b, *e);
return;
}

Or saving at least one of the memcpy's in the out of place syntax?

template<class T> T EndianReverse(T t)
{
T result=t; // "hides" a memcpy.
unsigned char* tp = reinterpret_cast<unsigned char *>(&result);
for (unsigned char *b = tp, *e = tp + sizeof(T) - 1; b < e; ++b,
--e) std::swap(*b, *e);
return result;
}

Shouldn't this make a difference, especially if it is inlined?


Oh yes, I'll be it does, but in 'comp.lang.c++' it's customary to
suggest only _proper_ solutions, whose behaviour is well-defined
according to the International Standard of the C++ language. Both
your examples have undefined behaviour.

V
--
Please remove capital As from my address when replying by mail
Mar 18 '06 #6
Victor Bazarov wrote:
Fabio Fracassi wrote:
Victor Bazarov wrote:
template<class T> T EndianReverse(T t)
{
unsigned char uc[sizeof t];
memcpy(uc, &t, sizeof t);
for (unsigned char *b = uc, *e = uc + sizeof(T) - 1; b < e;
++b, --e) std::swap(*b, *e);
memcpy(&t, uc, sizeof t);
return t;
}

Why not do it inplace?


Because the behaviour in _your_ case is undefined. You're *not*
allowed to use the pointer obtained from 'reiterpret_cast' for
anything _except_ converting back to what it was.


And what exactly is the point in converting it back and forth, without doing
anything in between?
Besides, the call to memcpy does two implicit casts, one from (T*) to
(void*) and one from (void*) to (unsigned char*), which is what allows you
to interpret the data as a series of bytes. Effectively your doing an
implicit cast from (T*) to (unsigned char*) with the memcpy. AFAIK,
reinterpret_cast does the same, albeit without the copying.
template<class T> void InplaceEndianReverse(T& t)
{
unsigned char* tp = reinterpret_cast<unsigned char *>(&t);
for (unsigned char *b = tp, *e = tp + sizeof(T) - 1; b < e; ++b,
--e) std::swap(*b, *e);
return;
}
[sniped one simmilar example] Shouldn't this make a difference, especially if it is inlined?


Oh yes, I'll be it does, but in 'comp.lang.c++' it's customary to
suggest only _proper_ solutions, whose behaviour is well-defined
according to the International Standard of the C++ language. Both
your examples have undefined behaviour.


I think my example's have exactly the same behaviour as yours. We both let
the compiler interpret a typed pointer as another typed pointer. This might
be implementational defined behaviour, but I don't see a way around this.

Fabio

Mar 19 '06 #7
Fabio Fracassi wrote:
Victor Bazarov wrote:
Fabio Fracassi wrote:
Victor Bazarov wrote:

template<class T> T EndianReverse(T t)
{
unsigned char uc[sizeof t];
memcpy(uc, &t, sizeof t);
for (unsigned char *b = uc, *e = uc + sizeof(T) - 1; b < e;
++b, --e) std::swap(*b, *e);
memcpy(&t, uc, sizeof t);
return t;
}

Why not do it inplace? Because the behaviour in _your_ case is undefined. You're *not*
allowed to use the pointer obtained from 'reiterpret_cast' for
anything _except_ converting back to what it was.


And what exactly is the point in converting it back and forth, without doing
anything in between?


If there's no point, then do not do it.
Besides, the call to memcpy does two implicit casts, one from (T*) to
(void*) and one from (void*) to (unsigned char*),
No. The call converts to void* only.
Anything else happens inside the implementation of memcpy.
And memcpy is an implementation problem.

Sure, most implementations will do what you say. But it is not guaranteed.
to interpret the data as a series of bytes. Effectively your doing an
implicit cast from (T*) to (unsigned char*) with the memcpy. AFAIK,
reinterpret_cast does the same, albeit without the copying.
That is what happens on most implementations, and on most
implementations your code actually does work.

Still there's nothing in the language definition that makes it
guaranteed. If I write a compiler that will do things differently, it
will still be a perfectly legal compiler.
I think my example's have exactly the same behaviour as yours. We both let
the compiler interpret a typed pointer as another typed pointer. This might
be implementational defined behaviour, but I don't see a way around this.


No. That is what your code tries to do. And is not legal.
His code converts to void* and calls memcpy. What happens inside memcpy
is that memory content is copyed. Without any type cast. The cast inside
memcpy is that of a magic spell.
Mar 19 '06 #8
AnalogFile wrote:
Fabio Fracassi wrote:
Victor Bazarov wrote:
Fabio Fracassi wrote:
Victor Bazarov wrote:

> template<class T> T EndianReverse(T t)
> {
> unsigned char uc[sizeof t];
> memcpy(uc, &t, sizeof t);
> for (unsigned char *b = uc, *e = uc + sizeof(T) - 1; b < e;
> ++b, --e) std::swap(*b, *e);
> memcpy(&t, uc, sizeof t);
> return t;
> }
>
Why not do it inplace?
Because the behaviour in _your_ case is undefined. You're *not*
allowed to use the pointer obtained from 'reiterpret_cast' for
anything _except_ converting back to what it was.


And what exactly is the point in converting it back and forth, without
doing anything in between?


If there's no point, then do not do it.


What is the point of having it in the language then? And how could I solve
such problems without relying on undefined behaviour?
Besides, the call to memcpy does two implicit casts, one from (T*) to
(void*) and one from (void*) to (unsigned char*),


No. The call converts to void* only.
Anything else happens inside the implementation of memcpy.


I don't think so. memcpy doesn't know anything about types, and does no
casting whatsoever. Its signature is "void* memcpy(void* dest, const void*
src, size_t n);". So if someone uses a typed pointer in memcpy's dest
parameter there is an implicit cast from void* to the type which was used.

As long as the cast doesn't change the bit pattern of the pointed to values
this operation is save.

Fabio

Mar 20 '06 #9
Fabio Fracassi wrote:
AnalogFile wrote:
Fabio Fracassi wrote:
Victor Bazarov wrote:

Fabio Fracassi wrote:
> Victor Bazarov wrote:
>
>> template<class T> T EndianReverse(T t)
>> {
>> unsigned char uc[sizeof t];
>> memcpy(uc, &t, sizeof t);
>> for (unsigned char *b = uc, *e = uc + sizeof(T) - 1; b < e;
>> ++b, --e) std::swap(*b, *e);
>> memcpy(&t, uc, sizeof t);
>> return t;
>> }
>>
> Why not do it inplace?
Because the behaviour in _your_ case is undefined. You're *not*
allowed to use the pointer obtained from 'reiterpret_cast' for
anything _except_ converting back to what it was.
And what exactly is the point in converting it back and forth, without
doing anything in between? If there's no point, then do not do it.

What is the point of having it in the language then?


I wrote "if" there's no point. It's in the language for those cases
where there actually is a point.
And how could I solve
such problems without relying on undefined behaviour?
Use the system library.
Besides, the call to memcpy does two implicit casts, one from (T*) to
(void*) and one from (void*) to (unsigned char*),

No. The call converts to void* only.
Anything else happens inside the implementation of memcpy.


I don't think so. memcpy doesn't know anything about types, and does no
casting whatsoever.


memcpy is part of the system and what it does or does not you cannot
say, except for the documented side effect of copying underlying bytes
from source to destination.
Its signature is "void* memcpy(void* dest, const void*
casting whatsoever. Its signature is "void* memcpy(void* dest, const void*
src, size_t n);". So if someone uses a typed pointer in memcpy's dest
parameter there is an implicit cast from void* to the type which was used.


sorry. I do not understand the above.

Mar 20 '06 #10
AnalogFile wrote:
Fabio Fracassi wrote:
memcpy is part of the system and what it does or does not you cannot
say, except for the documented side effect of copying underlying bytes
from source to destination.
Its signature is "void* memcpy(void* dest, const void*
casting whatsoever. Its signature is "void* memcpy(void* dest, const
void* src, size_t n);". So if someone uses a typed pointer in memcpy's
dest parameter there is an implicit cast from void* to the type which was
used.


sorry. I do not understand the above.


I'm just saying that memcpy is not resposible for the reinterpreting of the
pointer types, but that it happens implicitly at the function call, i.e

T1* t1p;
T2* t2p;
memcpy (t2p, t1p, sizeof(T1));

is equivalent to:

T1* t1p;
T2* t2p;

void * v1p = (void*) t1p;
void * v2p = (void*) t2p;
memcpy (v2p, v1p, sizeof(T1));

After writeing this I see the subtle difference between this way an what I
have written, because in this case the "backward" cast from (void*) to
(T2*) never happens, because t2p already holds the correct address.

Now does the standard really not guarantee that the pointed to memory is
left alone when I do an reinterpret_cast? Could you point me the right
section where I could look this up?

I'm not trying to be argumentative, but I can't belive that something as
basic as an inplace endianess reversal can't be done without resorting to
undefined behaviour or system specific libraries. If it is I consider this
a Defect.

Fabio



Mar 21 '06 #11
Fabio Fracassi wrote:
Its signature is "void* memcpy(void* dest, const void*
casting whatsoever. Its signature is "void* memcpy(void* dest, const
void* src, size_t n);". So if someone uses a typed pointer in memcpy's
dest parameter there is an implicit cast from void* to the type which was
used. sorry. I do not understand the above.


I'm just saying that memcpy is not resposible for the reinterpreting of the
pointer types, but that it happens implicitly at the function call, i.e

T1* t1p;
T2* t2p;
memcpy (t2p, t1p, sizeof(T1));

is equivalent to:

T1* t1p;
T2* t2p;

void * v1p = (void*) t1p;
void * v2p = (void*) t2p;
memcpy (v2p, v1p, sizeof(T1));

After writeing this I see the subtle difference between this way an what I
have written, because in this case the "backward" cast from (void*) to
(T2*) never happens, because t2p already holds the correct address.


Neither of the above sequences ever does any backward cast from void*
They in fact are perfectly equivalent.
Now does the standard really not guarantee that the pointed to memory is
left alone when I do an reinterpret_cast? Could you point me the right
section where I could look this up?
I'm again not sure I understand you.
If I get it right then, the "pointed to" memory does not change. Not at
the time of the cast.
I'm not trying to be argumentative, but I can't belive that something as
basic as an inplace endianess reversal can't be done without resorting to
undefined behaviour or system specific libraries. If it is I consider this
a Defect.


If you think hard at it you realize that the very concept of "endianness
reversal" is totally system dependent.

You are assuming that the system does have some sort of endianness to
begin with. Like a 4 bytes value is either stored as 1234 or 4321. And
probably you also assume values to be 2s complement. But as far as the
language is concerned it may be 1423 and not be 2s complement!

Mar 22 '06 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Joe C | last post by:
I have some code that performs bitwise operations on files. I'm trying to make the code portable on different endian systems. This is not work/school related...just trying to learn/understand. ...
8
by: Perception | last post by:
Hello all, If I have a C-like data structure such that struct Data { int a; //16-bit value char; //3 ASCII characters int b; //32-bit value int c; //24-bit value }
14
by: ThazKool | last post by:
I want to see if this code works the way it should on a Big-Endian system. Also if anyone has any ideas on how determine this at compile-time so that I use the right decoding or encoding...
2
by: bhatia | last post by:
Hello all, If I have a C-like data structure such that struct Data { int a; //16-bit value char; //3 ASCII characters int b; //32-bit value int c; //24-bit value }
25
by: Frederick Gotham | last post by:
I was intrigued by someone the other day who posted regarding methods of "mirror-imaging" the bits in a byte. I thought it might be interesting to write a fully-portable algorithm for...
33
by: raghu | last post by:
Is it possible to know whether a system is little endian or big endian by writing a C program? If so, can anyone please give me the idea to approach... Thanks a ton. Regards, Raghu
8
by: ma740988 | last post by:
Data stored on a storage device is byte swapped. The data is big endian and my PC is little. At issue: There's a composite type ( a header ) at the front of the files that I'm trying to read in....
23
by: guthena | last post by:
Write a small C program to determine whether a machine's type is little-endian or big-endian.
23
by: Niranjan | last post by:
I have this program : void main() { int i=1; if((*(char*)&i)==1) printf("The machine is little endian."); else printf("The machine is big endian."); }
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.