- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
My first guess is this comes from someone who was accustomed to write win32 code in which zeroing a struct with memset is more or less the standard way of doing this
Admin
Pendantry: the family of
struct sockaddr_in
must beAF_INET
no matter which OS you're running on.Pendantry 2: If you're running Linux/390 (yes, Linux can be run on a zSystem, the spiritual inheritor of the 1960s System/360),
'0'==0xF0
if your char type is unsigned...Admin
It's pretty much standard (but not universal) everywhere to use
memset
, but it's usual to use0
absolutely everywhere.'0'
is ... unusual.Admin
@Steve The Cynic: Pedantry: "pendantry" is not a word.
Admin
Oh pudin9, you're such a pendant!
(TRWTF is of course C)
Admin
Wow, I saw it right away, it was like a speed bump that hadn't been painted in years, so you didn't see it and drove over it at full speed. But then my thing is embedded, so little details like 0 vs '0' tend to be important. (And I still see no point in '\0' vs 0, it's like using "if (1=foo)" because 1993-era compilers can't catch = vs ==)
Admin
I'm guessing the author saw the pattern
memset(&struct, '\0', sizeof(struct))
elsewhere. Then, in trying to imitate it, neglected the backslash that makes the value the null control character (0 in ASCII), rather than the character '0'.Another mystey is why some C programmers insist on using control character literals when integers would do just fine.
Admin
There are reasons. (You may regard them as insufficient, but still.)
Consider trying to find all instances of a memset (as in this case) where the setting value is actually zero. Grep for memset and count. Grep for backslash zero and count. If the counts are the same, you're perfectly cromulent.
Now try to do that without the backslash. It's far more prone to error.
Equally, if I'm looking for eol characters, I would prefer them to be referenced as control characters, not as 13 or 10 or (in MS-speak) a combination of the two. You're going to find an awful lot of false positives in a million lines of code, otherwise.
I'm not recommending this for anything other than C or C++, but if you're working at a sufficiently low level, you genuinely need whatever clarity you can get.
Admin
I remember that in my youth when I was still dabbling in C/C++ (that was over 15 years ago) I also zeroed-out all the structs that I used. I don't remember doing it for this particular struct, and I was working predominantly on Windows, but still. The idea was that most of the time I just needed to set a few members of a struct and leave the rest as 0 anyway, so a memset + setting a few individual fields was the way of least typing. And future-proof too, if someone decided to change the struct down the road. But, yeah 0, not '0'. :)
Admin
For zero, I agree (outside of some stylistic consistency considerations), but for values greater than 0x7F, the difference between e.g.
0xA0
and'\xA0'
can be of critical importance if you haven't added-f-unsigned-char
or equivalent to the compiler command line.Admin
I know they're equivalent, but I believe that using
'\0'
rather than0
is appropriate when you're assigning or comparing achar
.But this WTF does point out that it's easy to typo this as
'0'
and get the wrong result. That's what testing is for.Admin
For control characters (well, those in the 0-31 range for control characters in ASCII, anyway), it's sort of OK, except if you're comparing a variable known to be a character (type is
char
) to a number, which looks odd to my way of thinking.If the values are greater than 0x7F, the discrepancies noted above can bite you. If you haven't turned on the "
char
by default behaves as if it is unsigned" compile option(1),0xA0 != '\xA0'
because the character version is negative.(1) The standards leave this option's default state to the compiler-writer's discretion.
Admin
And dictionaryish claims this:
pendantry is the unseasonable ostentation of learning. It may be discovered either in the choice of a subject or in the manner of treating it. Samuel Johnson
Personally, I hearby define "pendantry" as the art of making pendants (jewelry). And there's already a Jewelry store in Melbourne called "The Pendantry."
Admin
It has been my experience (with 2 different programmers) that they use literals so that there is no confusion when someone else reads the code because they think they're the only people in the Universe who know how the ASCII chart works.
Admin
Does negative ^G make a sound?
Admin
Samuel Johnson (bless him) was well-known for making extremely verbose jokes in his dictionary, and also for a smidgeon here or there of failing to cross-check.
In this case he very definitely meant "pedantry." And I would further argue that he meant "unreasonable," not "unseasonable," because the latter means nothing at all in context and the former can be understood by any seasonable English speaker.
Keep swinging that pendant!
Admin
Of course, the real problem is the socket functions - all requiring you to use "bad" programming practices as standard. Like casting. One shouldn't need to cast except in exceptional circumstances. Unless you're using sockets, in which case, casts are perfectly normal and required in order to actually do anything.
Anyhow, Windows is usually something like SOMETHING something; memset(&something, 0, sizeof(something)); // ZeroMemory() is a "native" Windows API for this too something.szLen = sizeof(something);
To version structures and have binary compatibility, WIndows has a size attribute you must set on structs so when they get extended, the code can handle it. Except of course, then you have to deal with SOMETHINGEX, SOMETHINGEX2, ...because that's the way they went instead of going with longer structs.
Admin
Forum memes sometimes leak. It most certainly is a word in the context in which it was coined (as a joke).
Admin
Does negative ^G make a sound?
Admin
What forum?
Admin
I think if you're comparing characters to particular control characters, your code will be actually be saying what it is doing if you use e.g. '\n', rather than whatever number it is. Otherwise the readability of your code is down to how much the next person to look at it works directly with ASCII all the time. E.g. I'm familiar with ASCII, but can't tell you off the top of my head what any of the control characters map to, because I don't actually use them all that often.
If you're zeroing out memory, using 0 instead of '\0' is clearer. It just so happens that '\0' maps to 0, but that's not what your code is doing. You aren't filling the memory with the null character, you are filling it with zeroes.
Admin
Sooo… reading the comments, my takeaway is that C##23 needs a way for a datatype to override what memset does to it, a la operator overloading, so in this case, it could set it all to zero apart from the field that needs to be AF_INET?
Admin
"Without context, I suspect this was programming by incantation: someone learned the hard way that variables in C don't start with a known value, "
Objects with automatic storage duration and no initializer have inderterminate values. Anythign with static storage duration and no initializer is 0-initialized.
See: https://en.cppreference.com/w/c/language/initialization (implicit initialization)
Admin
The horrid thing is MSVC auto-fills things with 0's if in Release mode, but something else when in Debug.
Admin
I would guess that's because '\0' is a char, while 0 is an int. But I'm only guessing. And there would be better ways on ensuring a char.
Admin
Yes, the what forum; what.thedailywtf.com
Admin
Filling uninitialized values to something other than 0 is supposed to help find errors, as a lot of the time, it's the 0 fill that masks the uninitialization.
Admin
It's because 0 is an integer: a numeric type of machine-defined size, usually 2 or 4 bytes. '\0' is a byte.
In early C, the char data type was strictly defined to be a byte. Void pointers didn't exist; char pointers were used instead (i.e., pointers to a sequence of bytes).
"Char == byte" is maintained for backwards compatibility these days, but that equivalence is firmly ingrained in the minds of some old-school developers, too. To them, it just makes more sense to fill a byte range with a byte value rather than an integral value.