Comment On Please Think Twice

"While reviewing some of our older code," Rob Jacobs wrote, "I stumbled upon this." [expand full text]
« PrevPage 1 | Page 2 | Page 3Next »

Re: Please Think Twice

2008-08-04 08:01 • by Bedders (unregistered)
Don't think twice, it's alright

Re: Please Think Twice

2008-08-04 08:03 • by snoofle
I've done some similar coding early on in my career because it seemed like a good idea at the time, but I always put in a few words as to what I was trying to accomplish and why...

Re: Please Think Twice

2008-08-04 08:03 • by Mad_Gouki (unregistered)
"no, no, really, it's the other rjacobs"

Re: Please Think Twice

2008-08-04 08:11 • by Ikke (unregistered)
Please think twice before reading this post.

Re: Please Think Twice

2008-08-04 08:21 • by ParkinT
THAT IS UNCONSCIONABLE!
That another developer would check in a change under Rob Jacobs' name!

Re: Please Think Twice

2008-08-04 08:24 • by danskal
Ok, so wtf is the point of this code?

Re: Please Think Twice

2008-08-04 08:25 • by The Sussman (unregistered)
You shouldn't leave your computer logged in and all that when you go get your bowl of ramen, man.

Captcha: sino, just like the ramen.

Re: Please Think Twice

2008-08-04 08:25 • by Mark V Shaney (unregistered)
The beauty of C is that you can write such code when you really need it.

Note that it is considered more elegant to use an union to store a float into a char array.

Re: Please Think Twice

2008-08-04 08:26 • by Fred (unregistered)
So what's a better way of storing the binary representation of a float into a byte array?

Re: Please Think Twice

2008-08-04 08:26 • by akatherder
And thus begins the long road to a schizophrenic breakdown.

Re: Please Think Twice

2008-08-04 08:29 • by Survey User 2338 (unregistered)
I would say that this is pretty typical. Most coders think their code is soooo good that anyone else (read lesser mortal) would need to think twice to improve their code. BTW, the emoticon is priceless.

Please think twice before trying to improve on this comment...

:^p

Re: Please Think Twice

2008-08-04 08:30 • by Ginger kid (unregistered)
I was asked to write code like that once to put integers into a linux kernel driver without using IOCTL.

Funny after we got it working that way we ended up using IOCTL instead anyway.

Re: Please Think Twice

2008-08-04 08:32 • by Gieron
I like doing stuff like this:

// DO NOT CHANGE! VERY IMPORTANT!
private static readonly int magicNumber = 62892;
Where, of course, the actual value is unimportant.

Re: Please Think Twice

2008-08-04 08:32 • by amischiefr
Now, while we all make mistakes and sometimes they are pretty stupid I have to ask one questions: who the hell in their right mind posts their own WTF's?

Re: Please Think Twice

2008-08-04 08:36 • by MRAB (unregistered)
In an application I was maintaining I found the well-intentioned statement:

buffer[strlen(buffer)] = '\0';

Re: Please Think Twice

2008-08-04 08:39 • by JS (unregistered)
209903 in reply to 209899
amischiefr:
Now, while we all make mistakes and sometimes they are pretty stupid I have to ask one questions: who the hell in their right mind posts their own WTF's?



Honest people?

Re: Please Think Twice

2008-08-04 08:46 • by SenTree
209905 in reply to 209893
Mark V Shaney:
The beauty of C is that you can write such code when you really need it.

Note that it is considered more elegant to use an union to store a float into a char array.

At this very moment, I'm refactoring a block of floats into unions because a very late new requirement (6 years out-of-date!) forces me to jam a load of int32s into a structure I cannot extend, on pain of... pain. I already have a magic 'convert anything 32-bit to anything else' union. I just love embedded C on a small processor !

Re: Please Think Twice

2008-08-04 08:47 • by Tringi (unregistered)
209906 in reply to 209903
JS:
amischiefr:
Now, while we all make mistakes and sometimes they are pretty stupid I have to ask one questions: who the hell in their right mind posts their own WTF's?

Honest people?

Those are few and far between these days... :-(

Re: Please Think Twice

2008-08-04 08:53 • by troels (unregistered)
209909 in reply to 209901

In an application I was maintaining I found the well-intentioned statement:

buffer[strlen(buffer)] = '\0';

argh!

Re: Please Think Twice

2008-08-04 08:53 • by Thief^
209910 in reply to 209894
Fred:
So what's a better way of storing the binary representation of a float into a byte array?

*((float*)(&x[4])) = value;
maybe?

Re: Please Think Twice

2008-08-04 09:07 • by Erik (unregistered)
This would NEVER happen to me! NEVER, I TELL YA!

Re: Please Think Twice

2008-08-04 09:07 • by Anrs (unregistered)
209918 in reply to 209910
Thief^:
Fred:
So what's a better way of storing the binary representation of a float into a byte array?

*((float*)(&x[4])) = value;
maybe?


memcpy(&x[4], &value, sizeof value);

This should also save you from some crashes due to unaligned access.

Re: Please Think Twice

2008-08-04 09:10 • by TheRider
209921 in reply to 209905
SenTree:
Mark V Shaney:
The beauty of C is that you can write such code when you really need it.

Note that it is considered more elegant to use an union to store a float into a char array.

At this very moment, I'm refactoring a block of floats into unions because a very late new requirement (6 years out-of-date!) forces me to jam a load of int32s into a structure I cannot extend, on pain of... pain. I already have a magic 'convert anything 32-bit to anything else' union. I just love embedded C on a small processor !
Suggestion: To save space, only use 31 bits for every int32 (offset every following int32 by -1 bit). This way you can stuff another int32 every 31st int32's. The 32nd bit is very rarely used anyway...

Re: Please Think Twice

2008-08-04 09:20 • by Matt (unregistered)
209924 in reply to 209899
amischiefr:
Now, while we all make mistakes and sometimes they are pretty stupid I have to ask one questions: who the hell in their right mind posts their own WTF's?



Someone who has learned the errors of his past ways.

He hopes to atone for his WTF sins by repenting and sharing with us. We can mock him, then he will forgiven and saved from Robot Hell. (Thats where WTF coders go)

Re: Please Think Twice

2008-08-04 09:22 • by SenTree
209925 in reply to 209921
TheRider:
Suggestion: To save space, only use 31 bits for every int32 (offset every following int32 by -1 bit). This way you can stuff another int32 every 31st int32's. The 32nd bit is very rarely used anyway...

Only for the SIGN ! (or did you mean the other end ?). Good laugh, though.

Seriously, it's not the space that's the problem. We have a distributed multi-processor system with some associated PC software, all of which relies on the communications packets and configuration records not changing. I have to implement a backwards-compatible fix, otherwise I have to rewrite a hell of a lot more code - and deploy it in the field. Since the 'field' includes Siberian coalmines, and we have no remote update system, and I'm the only person qualified to do it, that ain't gonna happen.

Re: Please Think Twice

2008-08-04 09:22 • by brazzy
209926 in reply to 209893
Mark V Shaney:
The beauty of C is that you can write such code when you really need it.

The horror of C is that it allows you to just say "It may be ugly, but I really need it" rather than spend effort and find a better way (which may involve refactoring).

Re: Please Think Twice

2008-08-04 09:29 • by c-- (unregistered)
209929 in reply to 209926
brazzy:
Mark V Shaney:
The beauty of C is that you can write such code when you really need it.

The horror of C is that it is really ugly.


Fixed.

Really though, I don't like ampersands everywhere.

Re: Please Think Twice

2008-08-04 09:31 • by OperatorBastardusInfernalis (unregistered)
209931 in reply to 209905
Implicit unions are MUCH cooler:







#include <math.h>



template <class A, class B> union union_pair

{

A first;

B second;

union_pair(const A &init) : first(init) { }

union_pair(const B &init) : second(init) { }

union_pair &operator=(const A &val) { first = val; return *this; }

union_pair &operator=(const B &val) { second = val; return *this; }

operator const A &() { return first; }

operator const B &() { return second; }

};

typedef union_pair<int, float> intfloat;



float InvSqrt(intfloat x)

{

float save = x;

x = 0x5f3759df - (x >> 1);

return 1.5f * pow(x, 1) - 0.5f * save * pow(x, 3);

}

Re: Please Think Twice

2008-08-04 09:42 • by diaphanein (unregistered)
209933 in reply to 209931
OperatorBastardusInfernalis:
Implicit unions are MUCH cooler:







#include <math.h>



template <class A, class B> union union_pair

{

A first;

B second;

union_pair(const A &init) : first(init) { }

union_pair(const B &init) : second(init) { }

union_pair &operator=(const A &val) { first = val; return *this; }

union_pair &operator=(const B &val) { second = val; return *this; }

operator const A &() { return first; }

operator const B &() { return second; }

};

typedef union_pair<int, float> intfloat;



float InvSqrt(intfloat x)

{

float save = x;

x = 0x5f3759df - (x >> 1);

return 1.5f * pow(x, 1) - 0.5f * save * pow(x, 3);

}


For you, Sir, there is most certainly a special place in hell. ;)

Re: Please Think Twice

2008-08-04 09:56 • by mark (unregistered)
209939 in reply to 209899
Because its funny.

Re: Please Think Twice

2008-08-04 09:58 • by jspenguin
I've done that before. I needed to send a float over a network connection, so I used something like that to pack it into a 32-bit int. GCC complains with the warning "dereferencing type-punned pointer breaks strict aliasing rules". I ignored it, since it normally works, but when I put the code in an inline function and turned optimization on, it stopped working. The proper way is to use a union:


inline uint32_t pack_float(float f) {
union {
float flt;
uint32_t intg;
} convert;
convert.flt = f;
return convert.intg;
}


No pesky warnings, and with optimization, it compiles to the same code.

Re: Please Think Twice

2008-08-04 09:59 • by John (unregistered)
209941 in reply to 209918
Anrs:
Thief^:
Fred:
So what's a better way of storing the binary representation of a float into a byte array?

*((float*)(&x[4])) = value;
maybe?


memcpy(&x[4], &value, sizeof value);

This should also save you from some crashes due to unaligned access.

Err, how do you know that x needs to be 4 bytes?

Technically, you should malloc x to the sizeof value.

Also you should take the address of x, not the address of x[4].

so, something like:
char *x = (char*) malloc(sizeof(value));
memcpy(&x,&value, sizeof(value));

Is that right? I haven't done C for about 6 year.

P.S. I HATE C

here's a thought...

2008-08-04 10:11 • by bex (unregistered)
if you are converting to a char, why the hell would you leave it in binary in the first place?! Isn't that just a bunch of wasted bytes? I mean, why send this over the wire:

"1111"

When you could just do this:

"15"

Or this:

"F"

Unless, of course, you don't own both ends of the pipe, and the stupid end requires a binary char array instead of hex...

Re: Please Think Twice

2008-08-04 10:11 • by tgape
209946 in reply to 209899
amischiefr:
Now, while we all make mistakes and sometimes they are pretty stupid I have to ask one questions: who the hell in their right mind posts their own WTF's?


Someone secure in their personhood.

Actually, I've found admitting my own WTFs to management generally results in a lessened impact, especially if I've come up with a fix before I approach management about it. For years, I kept the group I was in from having actual SLA requirements by generally meeting the service levels provided by other groups, and giving honest accounts of what went wrong along with plans to fix them, whenever we did have a problem.

One might think that this wouldn't be that useful a feat, since it required one to actually maintain good service. However, it allowed us several liberties:

1. If we wanted to do a change that wouldn't impact many people, we could do it any time of day - no change window needed.

2. We generally took our service outages in significant, unplanned chunks (planned service was generally performed with little to no outage). By announcing who dun it and what they were doing to fix it before most people knew about the problem, people generally didn't have time to get angry at an anonymous entity, so had nothing to transfer when they did find out. And, in general, people don't get angry as quickly at known persons with good reputations as they do at anonymous entities.

3. We didn't have to take the time to negotiate SLAs.

4. We didn't have to collect metrics to show we met our SLAs.

5. We didn't have to attend the quarterly SLA meeting.

6. We didn't get dinged for failing to meet our SLAs. (Note: we did get dinged for our various oopses - but groups with SLAs also got dinged for their various oopses; the SLA ding was in addition to those.)

7. When we finally did get an SLA (seems we got to the point where we were the only Corporate group without an SLA, and someone (VIDepartment) missed their SLA due to one of our outages - not that our outage was that long, but they were on the borderline), we were given significantly more latitude in setting our SLA.

Of course, not having an SLA did have one disadvantage:

1. We didn't get the bonus associated with meeting the SLA longer than anyone ever met their SLA, that we probably wouldn't have gotten anyway, because we wouldn't have met our SLA for that long.

Re: Please Think Twice

2008-08-04 10:18 • by Anrs (unregistered)
209948 in reply to 209941
John:
Anrs:

memcpy(&x[4], &value, sizeof value);

Err, how do you know that x needs to be 4 bytes?

Technically, you should malloc x to the sizeof value.

Also you should take the address of x, not the address of x[4].

so, something like:
char *x = (char*) malloc(sizeof(value));
memcpy(&x,&value, sizeof(value));

Is that right? I haven't done C for about 6 year.


Your snippet is wrong, but more importantly, your objection is wrong, too. The &x[4] is the destination in the existing char array, it has nothing to do with the size of a float.

Re: here's a thought...

2008-08-04 10:20 • by tgape
209950 in reply to 209945
bex:
if you are converting to a char, why the hell would you leave it in binary in the first place?! Isn't that just a bunch of wasted bytes?


You miss the point entirely. Maybe "compacted binary" would make more sense to you.

To put it in more specific terms, we're talking about a float (4 byte floating point) being stored as a 4-character string.

Generally, this is done for storage reasons, as the normal output routines for floating point convert them to a human-understandable string representation. One does not want to store the string "0.34832923" when one can just store 4 characters - especially since storing the string could introduce a rounding error.

Re: Please Think Twice

2008-08-04 10:41 • by java.lang.Chris;
209958 in reply to 209940
jspenguin:
I've done that before. I needed to send a float over a network connection, so I used something like that to pack it into a 32-bit int. GCC complains with the warning "dereferencing type-punned pointer breaks strict aliasing rules". I ignored it, since it normally works, but when I put the code in an inline function and turned optimization on, it stopped working. The proper way is to use a union:


inline uint32_t pack_float(float f) {
union {
float flt;
uint32_t intg;
} convert;
convert.flt = f;
return convert.intg;
}


No pesky warnings, and with optimization, it compiles to the same code.



And it wont work unless you always use it to transmit data between the same platforms. Consider what happens when endianness or floating point formats differ ... The correct solution would be to use XDR or ASN.1.

Re: Please Think Twice

2008-08-04 10:46 • by mth (unregistered)
209960 in reply to 209940
Alternative way would have been to give -fno-strict-aliasing option to gcc (I've done it with some older code written before gcc learned to broke^Woptimise such casts). Using uint32_t is good idea as the unsigned int is not 4 byte on all platforms.

Portable and readable solution would be of course to use memcpy. ;)

Re: Please Think Twice

2008-08-04 10:48 • by tL (unregistered)
It's rev1 to rev3. it was probably an import. Not everybody used vcs from the beginning of the project..

Re: Please Think Twice

2008-08-04 10:51 • by fatgeekuk (unregistered)
My C pointers are really rusty, but would not that code only work if a float takes up the same number of bits of memory as a float?

and, aren't floats normally 64 bits wide, and ints normally 32bits?

Re: Please Think Twice

2008-08-04 10:57 • by SenTree
209967 in reply to 209962
fatgeekuk:
My C pointers are really rusty, but would not that code only work if a float takes up the same number of bits of memory as a float?

A float always takes up the same number of bits of memory as a float (sorry, couldn't resist) ;/

fatgeekuk:
and, aren't floats normally 64 bits wide, and ints normally 32bits?

Only on systems where that's the case. Many embedded systems have 32 bit floats and 16 bit ints - in fact I can think of one which has 8 bit ints and (I think) 24 bit floats.

Re: Please Think Twice

2008-08-04 10:58 • by DeLos
209968 in reply to 209903
JS:
amischiefr:
Now, while we all make mistakes and sometimes they are pretty stupid I have to ask one questions: who the hell in their right mind posts their own WTF's?



Honest people?


People always lie.

(Sorry been watching the House DVDs recently)

Re: Please Think Twice

2008-08-04 11:00 • by fatgeekuk (unregistered)
209969 in reply to 209962
fatgeekuk:
My C pointers are really rusty, but would not that code only work if a float takes up the same number of bits of memory as a float?

and, aren't floats normally 64 bits wide, and ints normally 32bits?


hmmm, just checked.... I was wrong (at least I am maintaining todays average)

floats are 4bytes long. bugger.

I always thought.... well, never mind.

Re: Please Think Twice

2008-08-04 11:15 • by Ken B (unregistered)
209973 in reply to 209898
Gieron:
I like doing stuff like this:

// DO NOT CHANGE! VERY IMPORTANT!
private static readonly int magicNumber = 62892;
Where, of course, the actual value is unimportant.
In an application I maintain, which includes config/environment variables all starting with the same prefix, and all capital letters, I know some people run "strings" on new releases, looking for "hidden" config variables.

I've been tempted to add strings to the program which look like a config variable of the client's name (ie: "XYZ_CLIENT"), just to see if they'd say anything. I never had the nerve to actually try it, however.

Re: Please Think Twice

2008-08-04 11:18 • by Ken B (unregistered)
209974 in reply to 209909
troels:

In an application I was maintaining I found the well-intentioned statement:

buffer[strlen(buffer)] = '\0';
argh!
I use "argv" and "argc" all the time. What's "argh"?

Of course, on "Talk Like a Pirate Day", it's "aaaarrrghv".

Re: Please Think Twice

2008-08-04 11:24 • by Maks Verver (unregistered)
209976 in reply to 209918
I'd like to point out that of the various methods given in the reactions, Anrs method is one of the best:

void store(char *a, float f) {
memcpy(&a, &f, sizeof(float));
}

It has the big advantage over other methods given here, that it works for unaligned byte arrays. If you ever programmed for a CPU that disallows unaligned memory access (Windows CE/PocketPC is a common example) you should know how annoying it is when library code ported from the x86 crashes on unportable hacks like this.

If you think the solution using memcpy() is too slow, look at the code your compiler generates. All modern compilers contain special optimizations for common functions like memcpy(). The call above will actually be eliminated by the compiler and replaced by the efficient single assignment on platforms where it is safe to do so. So in practice, you get good performance, without sacrificing portability.

The downside of the memcpy() method is that it stores bytes in whatever order the local platform uses, which means that the resulting data isn't portable across platforms even if they use the same (IEEE) float representation.

To work around that, jspenguin's union trick helps,
although you still have to manually store the data in a character array:

void store(unsigned char *a, float f) {
uint32_t i = convert_float_to_uint(f);
/* Store in little endian byte order */
a[0] = i&255; i >>= 8;
a[1] = i&255; i >>= 8;
a[2] = i&255; i >>= 8;
a[3] = i&255; i >>= 8;
}

Re: Please Think Twice

2008-08-04 11:31 • by jspenguin
209978 in reply to 209958
java.lang.Chris;:
jspenguin:
I've done that before. I needed to send a float over a network connection, so I used something like that to pack it into a 32-bit int. GCC complains with the warning "dereferencing type-punned pointer breaks strict aliasing rules". I ignored it, since it normally works, but when I put the code in an inline function and turned optimization on, it stopped working. The proper way is to use a union:


inline uint32_t pack_float(float f) {
union {
float flt;
uint32_t intg;
} convert;
convert.flt = f;
return convert.intg;
}


No pesky warnings, and with optimization, it compiles to the same code.



And it wont work unless you always use it to transmit data between the same platforms. Consider what happens when endianness or floating point formats differ ... The correct solution would be to use XDR or ASN.1.


I forgot to add that I converted the resulting uint32_t to network byte order. So, the de facto protocol spec says, "A IEEE 754 single precision floating point number in network byte order". Almost *every* processor with an FPU uses IEEE 754. On processors that don't have an FPU, the floating point emulation that GCC links in uses IEEE 754.

This protocol is a real-time protocol for games -- strictly UDP. Using XDR would be overkill for this.

Re: Please Think Twice

2008-08-04 11:35 • by Edward Royce (unregistered)
Hmmm.

"Whoops."

Yeah did that myself once. Bitched about some lousy code in a project that had been done years before by contractors.

Turned out I was one of those contractors.

Whoops!

Re: Please Think Twice

2008-08-04 11:59 • by nobis (unregistered)
memcpy(x+4, &value, sizeof(value));

Re: here's a thought...

2008-08-04 12:08 • by bex (unregistered)
209995 in reply to 209950
To put it in more specific terms, we're talking about a float (4 byte floating point) being stored as a 4-character string.


ahh... makes more sense now. Thanks for the clarification.
« PrevPage 1 | Page 2 | Page 3Next »

Add Comment