Funny C Rules (And Low-Level Languages in general)
Re: Funny C Rules (And Low-Level Languages in general)
I generally return true on success for most functions, unless they can return more than 2 values. The compare functions return 0 for "true" or "equal" because they can return both positive and negative values, which matters when used for sorting. To reduce confusion, I've made my own functions for simple equality checks, like Q_streq(), so you don't have confusing code like "if (!strcmp(...".
Re: Funny C Rules (And Low-Level Languages in general)
Hmm. I'm not sure. Imagine every function having their own set of unique enums. Enums are almost never complete because they seek to represent something larger compressed to a single byte or 4/8 bytes.ericw wrote:Yeah the
dest->foo = src->foo;
VectorCopy(src->pos, dest->pos);
thing is awful. Using "const" liberally could detect mixing up the order of VectorCopy, but usually in Quake both source and dest are mutable.
IMO the 0=success, 1=failure, or -1=less, 0=same, 1=greater stuff is horrible legacy style, but often you have to have no choice because you're using API's that use that. The right way is C++11's "enum class" which don't implicitly convert to int.
At least with a numeric function I only have to ask, ok what does this return on success/failure and there are only 2-3 possibilities. A decent function will return a enum --- boolean!
Last edited by Baker on Sun Mar 01, 2015 3:11 am, edited 1 time in total.
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Funny C Rules (And Low-Level Languages in general)
0 for sucess makes sense in that you only have one success code, and multiple reasons for failure.
the alternative is the unix way, where <0 are errors, and >=0 are success codes. which is fine until you have 32bit+ results.
really its the difiference between a boolean and an (oob)enum. if the return value is defined as a bool of some kind, then its true for success. otherwise it should be 0 for success (as opposed to false).
and if its HRESULTS, use the FAILED or SUCCEEDED macros to provide the appropriate comparisons (note that these are consistant with the unix way).
VectorCopy is absurd. fix it BEFORE your engine becomes a sprawling monstrosity...
the alternative is the unix way, where <0 are errors, and >=0 are success codes. which is fine until you have 32bit+ results.
really its the difiference between a boolean and an (oob)enum. if the return value is defined as a bool of some kind, then its true for success. otherwise it should be 0 for success (as opposed to false).
and if its HRESULTS, use the FAILED or SUCCEEDED macros to provide the appropriate comparisons (note that these are consistant with the unix way).
VectorCopy is absurd. fix it BEFORE your engine becomes a sprawling monstrosity...
Re: Funny C Rules (And Low-Level Languages in general)
My interpolation macros uses (previous_src, dest, next_src), because that's what makes more sense for me.
Also, trying to guess the order of any functions is bad. I always take a look at the function declaration if I don't know/remember the order.
And imo, error codes are also bad. Errors should be treated internally, instead of hoping that the functions that called the functions that generated the errors will take care of them.
Btw, this is why I dislike the conventional return values used by stuff like strcmp. When using strcmp, the coder is essentially asking "does those strings match?", and a no is a valid answer for such a question, so in cases like this it makes no sense to assign the return values as if they were error codes.
To me, a "no" doesn't mean that the comparison performed by strcmp failed. A real failure would be if strcmp couldn't determine whether does the strings match or not.
Also, trying to guess the order of any functions is bad. I always take a look at the function declaration if I don't know/remember the order.
And imo, error codes are also bad. Errors should be treated internally, instead of hoping that the functions that called the functions that generated the errors will take care of them.
Btw, this is why I dislike the conventional return values used by stuff like strcmp. When using strcmp, the coder is essentially asking "does those strings match?", and a no is a valid answer for such a question, so in cases like this it makes no sense to assign the return values as if they were error codes.
To me, a "no" doesn't mean that the comparison performed by strcmp failed. A real failure would be if strcmp couldn't determine whether does the strings match or not.
Re: Funny C Rules (And Low-Level Languages in general)
strcmp and memcmp's -1, 0, 1 return values are great for sorting.mankrip wrote:When using strcmp, the coder is essentially asking "does those strings match?", and a no is a valid answer for such a question, so in cases like this it makes no sense to assign the return values as if they were error codes.
An example is FitzQuake's cvar list. Your own engine feeds (sorting by distance) qsort --- which requires a comparison function be supplied, what is essentially memcmp (although I think you slightly wrap it).
In C there is an isdigit macro. I guess an oversight in C is not supplying a "do strings match macro" like #define strmatch(a, b) (strcmp(a,b) == 0) because everyone rolls their own or whatever a quality name for it would be.
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Funny C Rules (And Low-Level Languages in general)
I guess the parameter order thing is all a matter of perspective. I always thought it made sense reading left to right, like with VectorCopy(A, B); I'm starting with A, and copying it to B.
Consts and better parameter names (like VectorCopy(in, out)) can help with this confusion.
It wasn't until I read some posts here with "A = B;" that it even crossed my mind that it could make sense for the destination to be on the left. I always thought the leftmost parameter being the output was necessary for functions like sprintf() where the parameters were variable, so you couldn't have the output parameter be at the end, and some other functions just followed that to try to be consistent, not because it was intuitive.
Consts and better parameter names (like VectorCopy(in, out)) can help with this confusion.
It wasn't until I read some posts here with "A = B;" that it even crossed my mind that it could make sense for the destination to be on the left. I always thought the leftmost parameter being the output was necessary for functions like sprintf() where the parameters were variable, so you couldn't have the output parameter be at the end, and some other functions just followed that to try to be consistent, not because it was intuitive.
Re: Funny C Rules (And Low-Level Languages in general)
I had never consciously thought about A = B either, which is a winner. That provides some extra clarity (for what I always believed).
I had become accustomed to memcpy and strcpy, therefore VectorCopy messed with my head. Generally, when I write functions, any function that alters something I tend to have it as the first parameter (the operand).
I had become accustomed to memcpy and strcpy, therefore VectorCopy messed with my head. Generally, when I write functions, any function that alters something I tend to have it as the first parameter (the operand).
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Funny C Rules (And Low-Level Languages in general)
mathematically, assignments commonly store to the righthand side. even quake's opcodes store to the right (yup, qcc interprets assignments the other way around from other 2-argument instructions).
really, consistancy is important.
even libc is inconsistant:
fputs(source, dest);
fprintf(dest, source);
personally I favour the object being updated as the first argument, because with stuff like fprintf, its easier to be consistant that way.
strlcpy(dest, source, destpart2); is annoying too.
really, consistancy is important.
even libc is inconsistant:
fputs(source, dest);
fprintf(dest, source);
personally I favour the object being updated as the first argument, because with stuff like fprintf, its easier to be consistant that way.
strlcpy(dest, source, destpart2); is annoying too.
Re: Funny C Rules (And Low-Level Languages in general)
Not really on-topic but ...I switched from Courier to the Liberation Mono font (which is fixed width). I get 15% more vertical lines. I can't tell any difference other than seeing more. I think the difference is mainly overhang/descent whatever you like to call what lowercase g, y, j do.
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Funny C Rules (And Low-Level Languages in general)
I macro away strlcpy and snprintf to conform to strlcpy (dst, src, sizeof(dst)) and snprintf(dst, sizeof(dst), ...)Spike wrote: strlcpy(dest, source, destpart2)
Mostly because I freakout that I might forget one of those parameters or put them in the wrong order.
I also occasionally use a macro that does a compile-time assert that screams if sizeof(dst) is sizeof(void *) to ensure that no instances are accidentally using a sizeof operation on a pointer.
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Funny C Rules (And Low-Level Languages in general)
A couple of notes:
12) Variables declared static or global variables have static storage duration and are initialized to zero
13) Due note that you cannot do sizeof int for instance, or any type, you do need parenthesis for those: sizeof(int)
12) Variables declared static or global variables have static storage duration and are initialized to zero
13) Due note that you cannot do sizeof int for instance, or any type, you do need parenthesis for those: sizeof(int)
Re: Funny C Rules (And Low-Level Languages in general)
Very interesting. I had to try that out.dimman wrote:13) Due note that you cannot do sizeof int for instance, or any type, you do need parenthesis for those: sizeof(int)
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Funny C Rules (And Low-Level Languages in general)
int y = 5;
These are are disallowed:
These are are disallowed:
But these are okint x = y++5; // No spaces, so the C parser isn't being space agnostic or figuring out this only makes sense if it is y + (+5)
int x = y--5; // No spaces
int x = y*-5; // No spaces
int x = y+-5; // No spaces
int x = y- -5; // Space between the minus signs
int x = y+ +5; // Space between the plus signs
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Funny C Rules (And Low-Level Languages in general)
We think of comments as being ignored. This isn't actually true.
They are interpreted as whitespace.
int x/*hello*/y = 5; // Error. If the comments were ignored, this line would be int xy=5;
They are interpreted as whitespace.
int x/*hello*/y = 5; // Error. If the comments were ignored, this line would be int xy=5;
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Funny C Rules (And Low-Level Languages in general)
The * for a pointer is often tacked on to the name.
But the * isn't part of the name.
static unsigned int * WINAPI myfunction (void); // Compiles. Notce placement to the left of WINAPI (the calling convention specifier)
static unsigned int WINAPI *myfunction (void); // Fails to compile. Can't have as part of the name.
Code: Select all
const char *mystring;
static unsigned int * WINAPI myfunction (void); // Compiles. Notce placement to the left of WINAPI (the calling convention specifier)
static unsigned int WINAPI *myfunction (void); // Fails to compile. Can't have as part of the name.
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..