The frequent invocations of RedHat upthread are weird and misplaced. _I_ did the initial BE testing for Jeff. Lots of people have access to BE systems and pretty much anyone who wants to can have access to one (for a couple bucks on ebay if nothing else). ... but nothing Jeff is doing makes handling the endlessness hard as directly evidenced by the fact that he got it running fine on BE without using one. Your 'solution' of pushing unions everywhere for that is an odd one and I'm happy to not work on your codebase.
Now that you've made your numerous complaints would you please cut it out? The tangent is going nowhere. If you want bitcoin software written to your particular, and somewhat odd, specifications feel free to do so yourself or to pay someone to do so.
I apologize for misattributing anyone's work. I didn't actually read the commit log. From the way you wrote I have to assume that Jeff did 100% of work and you did 100% of testing. It doesn't really matter who did what, so long as it is getting done at a reasonable frequency.
The "somewhat odd" comment is really strange. It is
the standard way to strenghten the C type system from structural equivalence to name equivalence. The type systems taxonomy is the standard curriculum of pretty much every CS or SE course at the university level. In fact the C++ code I posted above is patterned after the sample C/C++ code and a paper that was included with the "cfront" C++ compiler distribution from Bjarne Stroustrup that I've seen on some dusty VAX at my school. I didn't claim the autorship and in fact the requirement of not overusing type-cast-ing is one of the standard admonishments in the C/C++ project specifications.
On the other hand the 1995-1997 copyright dates on glib.h show that the base GTK/GNOME code was designed during the darkest days of GCC, predating the EGCS fork:
http://en.wikipedia.org/wiki/GNU_Compiler_Collection#EGCS_fork . At that time GCC was widely used as a baseline: it would reliably produce largest and slowest code after taking the longest time to build it; so almost anything looked better in comparison. From what I've heard from one of the Linux distribution maintainers was that many sub-optimal choices in open source packages were motivated by the desire to avoid tripping up GCC to produce very slow or incorrect code. Those days are long gone.
It really doesn't take an advanced computer science education to understand why poking holes in C/C++ type system by using unsafe casts is not a good architectural choice. It may be a good short term choice. Open source projects thrive on finding a group of people who while "scratching their own itch" actually scratch in the same place. It may well be the truth that many programmers here enjoy lookin at every uint32 and ponder wheteher to use it directly or through GUINT32_{TO,FROM}_LE macros.
I also know from the past experience that overall such people are not a majority, and would consider the above task a software engineering equivalent of digging diteches and filling them back in. For every one person who posted here there is at least 10 who read this thread with understanding. Of those 10 at least 2-3 will copy/paste the example code I wrote for a future reference.
So, yes, go ahead and play with the following somewhat longer example C code. Modify it to make mistakes and see which way is better for yourself.
#include
#ifdef _MSC_VER
#include
#define inline __inline
#define __builtin_bswap32 _byteswap_ulong
#endif
#ifdef __GNUC__
#define _byteswap_ulong __builtin_bswap32
#endif
/*
* type safe little endian
*/
union le_int {
unsigned char b[4];
int i;
};
/* little endian setter on little endian host */
static inline union le_int h2l_int(int a)
{
union le_int t;
t.i = a;
return t;
}
/* little endian getter on little endian host */
static inline int l2h_int(union le_int a)
{
return a.i;
}
/*
* type safe big endian
*/
union be_int {
unsigned char b[4];
int i;
};
/* big endian setter on little endian host */
static inline union be_int h2b_int(int a)
{
union be_int t;
t.i = _byteswap_ulong(a);
return t;
}
/* big endian getter on little endian host */
static inline int b2h_int(union be_int a)
{
return _byteswap_ulong(a.i);
}
/* excerpted from the Glib.h include tree */
typedef unsigned int guint32;
typedef signed int gint32;
#define GUINT32_SWAP_LE_BE(val) ((guint32) __builtin_bswap32 ((gint32) val))
#define GINT32_TO_LE(val) ((gint32) (val))
#define GINT32_TO_BE(val) ((gint32) GUINT32_SWAP_LE_BE (val))
#define GINT32_FROM_LE(val) (GINT32_TO_LE (val))
#define GINT32_FROM_BE(val) (GINT32_TO_BE (val))
/* end of Glib.h excerpt */
/* little endian type unsafe */
int lehmer1(int n)
{
int r = GINT32_TO_LE(1);
while (n--)
r = GINT32_TO_LE((16807 * GINT32_FROM_LE(r)) % 2147483647);
return GINT32_FROM_LE(r);
}
/* little endian type safe */
int lehmer2(int n)
{
union le_int r = h2l_int(1);
while (n--)
r = h2l_int((16807 * l2h_int(r)) % 2147483647);
return l2h_int(r);
}
/* big endian type unsafe */
int lehmer3(int n)
{
int r = GINT32_TO_BE(1);
while (n--)
r = GINT32_TO_BE((16807 * GINT32_FROM_BE(r)) % 2147483647);
return GINT32_FROM_BE(r);
}
/* big endian type safe */
int lehmer4(int n)
{
union be_int r = h2b_int(1);
while (n--)
r = h2b_int((16807 * b2h_int(r)) % 2147483647);
return b2h_int(r);
}
int main()
{
printf("%d\n",lehmer1(2112));
printf("%d\n",lehmer2(2112));
printf("%d\n",lehmer3(2112));
printf("%d\n",lehmer4(2112));
return 0;
}