Page 2 of 5

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Sun Mar 01, 2015 2:38 am
by jitspoe
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)

Posted: Sun Mar 01, 2015 3:09 am
by Baker
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.
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.

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!

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Sun Mar 01, 2015 3:10 am
by Spike
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...

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Sun Mar 01, 2015 7:04 am
by mankrip
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.

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Sun Mar 01, 2015 4:52 pm
by Baker
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.
strcmp and memcmp's -1, 0, 1 return values are great for sorting.

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.

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Sun Mar 01, 2015 11:04 pm
by jitspoe
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.

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Mon Mar 02, 2015 1:20 am
by Baker
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).

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Mon Mar 02, 2015 4:26 am
by Spike
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.

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Mon Mar 02, 2015 4:32 am
by Baker
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.

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Mon Mar 02, 2015 4:39 am
by Baker
Spike wrote: strlcpy(dest, source, destpart2)
I macro away strlcpy and snprintf to conform to strlcpy (dst, src, sizeof(dst)) and snprintf(dst, sizeof(dst), ...)

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.

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Tue Mar 03, 2015 1:53 pm
by dimman
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)

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Tue Mar 03, 2015 3:50 pm
by Baker
dimman wrote:13) Due note that you cannot do sizeof int for instance, or any type, you do need parenthesis for those: sizeof(int)
Very interesting. I had to try that out.

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Tue Mar 03, 2015 4:36 pm
by Baker
int y = 5;

These are are disallowed:
int 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
But these are ok
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

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Tue Mar 03, 2015 6:51 pm
by Baker
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;

Re: Funny C Rules (And Low-Level Languages in general)

Posted: Tue Mar 03, 2015 9:21 pm
by Baker
The * for a pointer is often tacked on to the name.

Code: Select all

const char *mystring;
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.