It's like when people define a 64MB buffer as something like:
#define BUFSIZE (64 * 1024 * 1024);
Even though you could've written 67108864, the former is far more comprehensible.
"[P]rograms must be written for people to read, and only incidentally for machines to execute." -- Abelson & Sussman, Structure and Interpretation of Computer Programs [1], strangely misquoted by Paul Graham [2]
[1] http://mitpress.mit.edu/sicp/full-text/sicp/book/node3.html
This also applies to the bit in the article about coercing return values, which I disagree with. Funnily enough, he mentions that K&R also recommend coercion, even though they have a small note that it's not necessary any more. Still makes for clearer programs.
I remember working on a Java codebase years ago where every string literal was defined in a Constants class - fair enough I guess. However, it had entries that looked like this:
public static String HTTP = "http";
public static String COLON = ":";
public static String SLASH = "/";
leading to code that looked like: url = Constants.HTTP + Constants.COLON + Constants.SLASH + Constants.SLASH +There's actually two problems with such code: one is that it doesn't actually make the code easier to read, but harder.
The other is more subtle: using constants like this is working at the wrong level of abstraction. The correct way to write this kind of code is to use a wrapper function which knows how to put together URLs, since there are lots of special rules to how URLs are put together (encoding, etc.) But a lot of people don't bother, and instead simply concatenate strings with a SLASH between them, and think that because they define the slash in some constant that makes the code correct.
Naturally, I like constants like POPCORN_PRICE = 12 or whatever. They add meaning to meaningless numbers.
I am on the fence for HOUR_PER_DAY and MINUTE_PER_HOUR, because they never change, but they at least add a certain security if you chain them together. bar = lengthInSeconds * SECONDS_IN_MINUTE * MINUTES_IN_HOUR * DAYS_IN_YEAR. In this case you can simply match. Seconds - Seconds, fits. Minute - Minutes, fits. Hour - days... wait, doesn't fit.
However, if you look at PROTOCOL + COLON + SLASH + SLASH versus "http://, there is just nothing added.
url = "http://" + ....
:-)One thing I know -- that person is dangerous. How do I know? I was (perhaps still am) that person. It was a bad habit and I am still trying to get rid it. It is a veiled show of immaturity and arrogance.
I once had to deal with code that did something like this:
return a ? b : c ? d : e ? f : g;
I'm not kidding. return a ? b :
c ? d :
e ? f :
g;
Side note: this does not work in PHP, as the operator is left-associative instead of right-associative there. The above in PHP would be evaluated as: return ((a ? b : c) ? d : e) ? f : g;
Which is almost never what you want. I can't even format this properly to convey intent.Because that sounds suspiciously like "potentially exploitable" to me.
The casting of the malloc() return value is something reasonable people can disagree about (by which I mean nerds can endlessly flame each other about). But here are some points:
* In C++, which Mozilla is written in, it is a compile time error to not cast, so most likely this blog post is just wrong. Conceivably, the file could have been a C file in an otherwise C++ project, but even in that case, it's at least understandable why the cast is there.
* If you have a macro that takes the type as a parameter:
#define alloc(type) ((type *)malloc(sizeof(type)))
then the casting is a good thing because it makes the compiler warn if you try to assign the result to the wrong pointer type.* It is true that if you forget to include the stdlib.h header, the cast will silence a useful warning about converting int to pointer.
(2) A terminating null character is placed at the end of strings, not at the end of allocated memory. malloc does not alter the memory before it returns a pointer to it; it is up to the programmer to ensure he is writing in the proper area.
Really, these sort of things are probably good in code: they make it explicit that you are dealing with char's, and not some other datatype. If left out, it may look like a bug, causing debugging hassles.
group->text = (char *) malloc(sizeof(char) * strlen(params->text));
if (group->text == NULL) {
res = MP_MEM;
}
strcpy(group->text, params->text);
I don't think that the sizeof(char) or the casting of the pointer are of any danger and increase readability (we are not coding to show how well we know the standard).The poster is right about the missing space in the malloc call for the NULL char, but I see a bigger threat calling a malloc with the size coming from a strlen: it can be really dangerous if somehow you miss a NULL terminator.
And again, same complain about the usage of strcpy. The standard gives us strncpy that put a limiting size in the copy operation.
_Personally I think that strcpy has to be avoided as a plague being a source of buffer overruns error as no other call in the C library._
T* t = malloc( sizeof *t );
It's no big deal, but it's just one less thing to change if you need to change the type. (I once had to go through some code changing longs to ints to make it run on a 64-bit machine. Were the mallocs written this way it might have been a bit easier.)And although I agree that his sizeof(char) rage is overblown, is the author's point about the zlib code not reasonable?
I think casting malloc is useless in C (not only semantically, but from a readability POV), and is generally correlated with poor C programming. As other mentioned, mozilla is in C++, so that does not apply.
This does not look like advice about coding for the real world, it seems to be about how to invest your time to maximise feelings of smug superiority.
But it is rather a legacy nowadays. No one should use it.
The problem is people are confusing the definition and the usage, because this particular type "char" was supposed to hold a numerical representation of a symbol, which in case of a multi-byte encoding is not 1 byte anymore.
So, sizeof(char) is always 1, and what they trying to say is sizeof(numeric-representation-of-a-symbol) which is not a concern of the C language.
A byte is always 8 bits, and therefore contains unsigned numbers 0 to 255 inclusive.
A char is always defined to be the base size of the machine.
By definition, therefore, sizeof(char) is always 1.
However, a char is not always 1 byte. On some machines a char can hold the values 0..511, and on others 0..65535. (for example)
That definitely isn't true. Historically, bytes went from 5 to 16 bits, it was just the number of bits required to handle a character.
If you want to talk specifically about 8-bit bytes in an architecture-independent manner, use the word "octet" (which happens to be the word french people generally use).
`char` is a technically independent (though often related) datatype defined as being >= 8 bits by the ANSI standard and the definition of `sizeof(char) == 1` is an axiom of the ANSI standard, not the consequence of anything but itself, though the standard definitely seems to confound (confuse?) chars and bytes:
2 The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant. 3 When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1. When applied to an operand that has array type, the result is the total number of bytes in the array.88) When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding.
The other reply to my comment (http://news.ycombinator.com/item?id=1666345) gets this right.
Again, apologies.
Coding at the bare-metal level is a very slow, tedious, error-prone and silly way to code unless you're doing, or have some external constraint that forces you to (and, no, efficiency isn't usually a reason not to use C++ or the STL, it almost always compiles to the same as using strcpy's and malloc's.)
-- Ayjay on Fedang/coding