Author Topic: C word  (Read 49397 times)

0 Members and 1 Guest are viewing this topic.

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: C word
« Reply #175 on: September 30, 2019, 06:30:26 am »
The above is also the best way to make a HOOD-ICE confused.

Thank god, the Greenhills CC reports an error and refuses to compile.

You canna do it, you wanna not do it, don't do it. PleaZe  :D

edit:
even DiabCC/PPC refuses to compile.
« Last Edit: September 30, 2019, 08:47:44 am by legacy »
 

Offline Gandalf_Sr

  • Super Contributor
  • ***
  • Posts: 1729
  • Country: us
Re: C word
« Reply #176 on: September 30, 2019, 08:30:12 am »
All of which leaves mere C mortals like me very confused.
If at first you don't succeed, get a bigger hammer
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17773
  • Country: fr
Re: C word
« Reply #177 on: September 30, 2019, 01:29:30 pm »
Try sizeof(int[x++]). x does get incremented. Do you know why?
Yes. The int[expression] part describes a type, an array of ints, and the expression part must be evaluated to determine the number of elements in that array.  The entire expression evaluates to the size of that array.

Bugger me if I know whether that is according to the C standard or not (i.e. whether the increment should be visible outside the expression or not); I gave up language-lawyerism a long time ago.  It is such a corner case I would not dare assume all C compilers get it right.  Seeing any kind of increment, decrement, or assignment in a sizeof expression is a red flag to me: something's afoot, and that expression must be fixed.

As Nominal said, in the atrocious case sizeof(int[x++]), the type that is passed here to sizeof is a variable-length array (something that was introduced in C99 and that I rarely ever use, but that's not the point), so the compiler needs to evaluate x. As x is post-incremented, sizeof would strictly NOT require the post-incrementation to occur to evaluate the size; but I'm willing to think it's undefined behavior territory here.

As nasty as this construct looks, it still picked my curiousity, so I checked this out in the C99 standard.
And, actually, this is defined behavior! So when in doubt - check what the standard says.

Quoting:
Quote
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.

Since the standard states that the operand is evaluated for VLAs, we can only assume that it's a FULL evaluation, not just a partial one for what would be strictly needed for sizeof (which could be hairier to implement that we may think anyway...)
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: C word
« Reply #178 on: September 30, 2019, 03:45:46 pm »
Yes, fully agreed with SiliconWizard above.

Perhaps some more waffling about the sizeof operator would be useful?  :P
If you are interested, the C99 standard with all corrigenda included is available as a PDF here.

The sizeof operator has two forms:
    sizeof (type)
    sizeof expression

The first form evaluates to the size of the type type.  It must not be an incomplete type, except that a structure with a flexible array member as the last member is allowed; then it evaluates to the size of the structure without that member (but including any padding before that member).
If the type is a variable-length array, then the expression specifying the array length is evaluated (C99 6.5.3.4p2 like SiliconWizard already explained above), and any side effects of that array length evaluation are visible outside the expression.

The second form evaluates to the size of the value the expression yields, but it cannot be a bit field or a function.  (Function pointer is fine.)
The expression itself is only evaluated for its type (unless it involves a variable-length array, in which case that length sub-expression is fully evaluated).  This means that if you want to know the size of the type that pointer p points to, use sizeof *p as it is always safe, even when p is NULL or undefined.

Even if you have something as odd as say struct foo ***p, you can use sizeof *p == sizeof (struct foo **), sizeof **p == sizeof (struct foo *), and sizeof *p = sizeof (struct foo).  Only the type matters.  No memory is ever examined, and the value of p is irrelevant.

As I already mentioned, I consider any increment, decrement, or assignment in the operand (right side) of a sizeof expression to be extremely suspicious: a sure sign of foul play.

There are three common patterns, that can confuse unaware C programmers.
  • Number of array elements
    When you have an array type, say
        sometype  my_array[MY_ARRAY_SIZE];
    you can use
        sizeof my_array / sizeof my_array[0]
    to obtain the number of elements in my_array.  The dividend is the number of bytes in the entire array, and the right side is the number of bytes in the first element in the array.
    This only works for array types with specific lengths.  It does not work for pointers, because the C compiler only knows the length of arrays at compile time; pointers do not have any such "array length" information associated with them, and there is no such information at run time by default (which is the reason you need to keep track of the length of many things yourself).

  • Robust/correct-size dynamic allocation
    When your code declares a pointer, say struct foo *p;, and you need to allocate memory for one such structure later on, it is useful to use
        p = malloc(sizeof *p);
    instead of p = malloc(sizeof (struct foo));, because we humans sometimes end up changing the type the p points to, but forget to update the type later in the sizeof expression later in the code.  The former form is more robust, and if you read it as "malloc the size of the thing p points to", it makes more sense, too.

  • Allocation of structures with flexible array members
    Let's say you create a string or byte array type,
        typedef struct {
            size_t  size;
            size_t  used;
            unsigned char  data[];
        } mystr;
    A function that creates a new one duplicating existing data can be written as
        mystr *mystr_create(const void *src, size_t len, size_t space)
        {
            mystr *result;
       
            result = malloc((sizeof *result) + len + space + 1);
            if (!result) {
                errno = ENOMEM;
                return NULL;
            }
           
            if (len > 0) {
                memcpy(result->data, src, len);
            }
           
            result->data[len] = '\0'; /* A convenience! */
            result->used = len;
            result->size = len + space + 1;
            return result;
        }
    Note that you often also see the equivalent result = malloc(sizeof (mystr) + len + space + 1);.  In the above snippet, the extra parentheses around sizeof *mystr is intended to clarify the expression for us humans; they are not strictly necessary. (For the compiler, the operand to sizeof is an unary expression, which means that sizeof a + b == (sizeof a) + b.)

Finally, when reading pointer types, split the definition at each *, read the type from rightmost part left, eplacing each * with "is a pointer to", to get the correct English human-readable definition.  For example, if you see something nasty like
    volatile struct bar *const *p;
you read it as "p is a pointer to a const pointer to a volatile struct bar".  A const pointer is a pointer that the code won't try to modify to point elsewhere, and volatile means the value can be changed at any time so the compiler must not generate code that caches/remembers the value. So, p points to a pointer that the code won't try to modify, and that pointer points to a struct bar whose value can change unexpectedly.  Both the members in that struct, and p itself, can be modified.
 
The following users thanked this post: Gandalf_Sr

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17773
  • Country: fr
Re: C word
« Reply #179 on: September 30, 2019, 04:04:06 pm »
Oh, the last part is important (although some people on here don't seem to even care about using const... ::) )

Don't confuse:
const TYPE *p;
with:
TYPE * const p;

 :D

In the former case, you can't write to the location pointed by p.
In the latter, you can write to the location pointed by p, but you can't modify p itself.

Of course you can mix both:

const TYPE * const p;

Have we lost anyone?
 

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: C word
« Reply #180 on: September 30, 2019, 05:40:13 pm »
.
« Last Edit: August 19, 2022, 02:32:17 pm by emece67 »
 

Offline Gandalf_Sr

  • Super Contributor
  • ***
  • Posts: 1729
  • Country: us
Re: C word
« Reply #181 on: September 30, 2019, 08:12:43 pm »
Oh, the last part is important (although some people on here don't seem to even care about using const... ::) )

Don't confuse:
const TYPE *p;
with:
TYPE * const p;

 :D

In the former case, you can't write to the location pointed by p.
In the latter, you can write to the location pointed by p, but you can't modify p itself.

Of course you can mix both:

const TYPE * const p;

Have we lost anyone?
You lost me, can you please add a bit more explanation?
If at first you don't succeed, get a bigger hammer
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17773
  • Country: fr
Re: C word
« Reply #182 on: September 30, 2019, 08:22:35 pm »
Well, when using pointers, there are two possible ways a qualifier (such as const) can be applied:
- to the pointer itself,
- to the data pointed to by the pointer.

To differentiate, the C grammar looks whether the qualifier is BEFORE or AFTER the "*" symbol.
When it's after, it applies to the pointer itself. When it's before, it applied to what's being pointed to.

A common use of const with pointers can be found even in std functions such as memcpy():
typical prototype is like:
Code: [Select]
void * memcpy(void *pDest, const void *pSrc, size_t nLength);
The second parameter is 'const void *', which basically means the buffer pointed to by pSrc should be treated as read-only inside the function. For the implementers of the function, that means the compiler won't let you modify the data pointed to by pSrc. For the users of the function, that means you can safely assume it will never modify the buffer you pass as the second argument.

 
The following users thanked this post: Gandalf_Sr

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: C word
« Reply #183 on: September 30, 2019, 09:02:14 pm »
Let's see:
    foo *p0;
    foo *const p1;
    const foo *p2;
    foo const *p3;
    const foo *const p4;
    foo const *const p5;

First of all, p2 and p3 have the exact same qualified type ("qualified" meaning the type including qualifiers like const or volatile), because you can put the const qualifier before of after the type name, and it'll still be the same thing.

Obviously, so have p4 and p5.

We cannot use foo *p6 const;, because the qualifiers must be listed before the variable name.

Pointer p1 is constant, but the thing it points to is not.  That is, p1 is a const pointer to foo.  This means that you cannot change the value of p1 , but you can modify the thing it points to.

Pointers p2 and p3 are pointers to const foo.  This means you can change the pointers (where they point to), but not the thing they point to.

Pointers p4 and p5 are const pointers to const foo.  This means you cannot change the pointers, nor the data they point to.



In function declarations and definitions, it is important to remember that in C, parameters are passed by value (but arrays decay to pointers), and any changes to the parameter values are only visible within the function, not to the caller.

To summarize, the differences between
    void  foo1(char *p) { ... }
    void  foo2(char *const p) { ... }
    void  foo3(const char *p) { ... }
    void  foo4(const char *const p) {...}
is that in the body part (...), foo2() and foo4() won't change the value of p; and foo3() and foo4() won't change the data pointed to by p.

You often see only foo1() and foo3() forms used, because current C compilers are smart enough to know when we don't try to modify the value of p, and do what they'd do if we had used foo2() and foo4() instead.  So, the compilers do not care much.  (This may not be true if you use a proprietary or old C compiler, though; you can check by compiling with and without, and comparing the generated object code.)

However, if the function is complicated, using foo2() and foo4() forms can help us humans, because then we know that the value of p (i.e, where it points to), will stay the same throughout the function; we know there isn't code that does say p++ or similar somewhere easily missed in the function body.
I personally like these even forms, because it helps me, and I do not trust myself to not make an arse of myself now and then; such practices help me catch my own stupidity.  And others', too, of course.



One interesting feature of C99 variable length arrays is that a function declaration like
    double  polynomial(const double x, const size_t n, const double coeff[n]);
is perfectly standard.  Within the function body, the compiler knows coeff is an array of n doubles, with n specified as the second parameter.
You do need to have the parameters that affect the array size before the array in the function parameter list, though; but it can be an expression like eg. 2*n+1.
(You can fudge the parameter order with a preprocessor macro, or use a wrapper function, but it can be VERY confusing unless well documented.)

This particular function is usually implemented as
    double  polynomial(const double x, const size_t n, const double coeff[n])
    {
        double  result = 0.0;
        double  arg = 1.0;
        for (size_t i = 0; i < n; i++) {
            result += coeff * arg;
            arg *= x;
        }
        return result;
    }
where we don't really need help from the compiler to check for array bounds; but this form allows a good compiler to check it at compile time, without run-time overhead!

It is much more useful when you do filters and such, accessing elements offset by an index, as a good compiler (gcc, clang) can usually detect if the indexes can pass outside the array bounds.  Also note how useful it is to see immediately that the function body won't modify x or n; they'll retain their values throughout the function.  (The coeff array is const, which means that the entries in it are not modified in the function; the "value" of coeff itself is constant, because arrays always decay to the pointer to its first element, and you cannot modify the array variable itself, only its entries.  That is, coeff++ is not allowed, because it is an array, and not a pointer.)

Furthermore, if you have say double *c;dynamically allocated for say k coefficients (k-1'th degree polynomial), you can call v = polynomial(x, c, k); because of how arrays decay to pointers, and the variable length array declaration like above "reconstitutes" it into an array for purposes of the called function.  Nice.
« Last Edit: September 30, 2019, 09:06:38 pm by Nominal Animal »
 
The following users thanked this post: Siwastaja

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: C word
« Reply #184 on: September 30, 2019, 09:19:43 pm »
Code: [Select]
void * memcpy(void *pDest, const void *pSrc, size_t nLength);
But note that using Hungarian notation for your variable and parameter names is, well, less than useful.

If you want to find the type of a variable, just use your code editor for that.  It is much better to use descriptive names, and leave the type out.  You see, if you trust the variable name, you risk creating bugs, because sometimes backwards compatibility requires the type of a variable to be changed, while the variable name must stay the same.  After the change, when someone needs to use that variable in a computation, they use the incorrect type based on the variable name.

The 32-bit to 64-bit shift (from ILP32 to LP64 or LLP64) was full of such bugs.  They hurt.  (Nowadays, we should use uintptr_t or intptr_t for unsigned or signed integer representations of pointers; size_t for sizes or lengths of in-memory things, and off_t for file sizes and positions.)

It's the same thing as trying to memorize, or being proud of remembering, library function prototypes.  memset(void *dest, int c, size_t n) is a perfect example.  The middle parameter is the byte value to be used to fill the region with, the last parameter being the size of that region in bytes; but would you be surprised to know that even in the Linux kernel, developers sometimes mix those two?

So no, don't use Hungarian notation, and don't try to memorize stuff.  Use your editor, and library references.  I like Linux map pages online for Linux, C99, and POSIX.1 stuff.  (The pages have a Conforming to section, which tell you which standards or systems provide the interface.)
« Last Edit: September 30, 2019, 09:21:18 pm by Nominal Animal »
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17773
  • Country: fr
Re: C word
« Reply #185 on: September 30, 2019, 09:58:07 pm »
This is yet another completely fruitless debate that serves no purpose whatsoever. This one is virtually endless, you'll find people with good arguments at either side, and it's all a matter of style. To each their own. Like the opening braces at the end of lines, that I find horrendous looking - but it's still the preferred style of many. (Oh, I think my style is actually close to Stallman's one - with what's happening recently, that's probably not "politically correct" either?  ;D )

Did it make my posted code less readable and my points less accurate? I don't think so. All that matters here.

I personally find it infinitely more readable, and any code not using this looks actually sloppy to me. It's absolutely NOT made to help writing code, but to help READing it afterwards, so letting that cause you bugs would be completely mind-fuckingly stupid. It's for readabiity questions. And if you use it, use it properly. I don't see any more odds of getting this wrong than adding a +1 when a -1 was required. A fuck-up is a fuck-up.

Of course everyone has different taste and views on what looks readable or not (mind you, most code I run into looks atrocious to me anyway). Readability has some level of subjectivity as well. Relying on a specific editor is nice, but it doesn't help readability. You don't read a book while inspecting each word in a dictionary, that would be awful, so, this way I get a better overall view. It's not a replacement for checking that I use types correctly either.

Frankly I absolutely don't care about what you think of it, or getting into the typical flame wars that have infested usenet before forums even existed. (I think this one was popular.) It has served me pretty well for years. Now if you like writing code in Eclipse with a dark theme, that would be also your choice. Not mine.
 

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: C word
« Reply #186 on: September 30, 2019, 11:58:03 pm »
.
« Last Edit: August 19, 2022, 02:32:34 pm by emece67 »
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: C word
« Reply #187 on: October 01, 2019, 01:24:31 am »
This is yet another completely fruitless debate that serves no purpose whatsoever.
Hey, if it works for you, go for it; no need to get your asbestos suit on.  :-+

As to coding style, including naming, I'm used to adjusting to the existing style guide; it definitely helps getting ones patches accepted.
My recommendation to those learning C is to try writing code using different coding styles, because that will help a lot when collaborating with others.
Hungarian notation (type prefix in variable names) is not at all rare in C code, so try it as well.

Much more important than that, is to write comments that describe the programmer intent -- what the code should accomplish --, instead of explaining what the code does.  Learning to write good, useful comments is an invaluable skill, and it is much easier to learn early than late.  Me myself, I'm still working on that.

Did it make my posted code less readable and my points less accurate? I don't think so. All that matters here.
It did not, that I agree; but, I think that when giving advice, we should consider the intuitive associations our advice is likely to generate.

For example, if you consider that space-after-sizeof thing I've suggested, it is not even style issue, but a tool to internalize that particular oddity: sizeof being an operator, and not a function.

I don't see any more odds of getting this wrong than adding a +1 when a -1 was required. A fuck-up is a fuck-up.
I disagree, because of the bug pattern that I described.  Because of architecture/hardware changes, the type of the variable has to be changed, but because of compatibility reasons, the variable name cannot be changed; thus, the prefix and real type are detached, and causes issues when one later on edits the code but does not realize that the prefix is incorrect.  That situation does not have any good fixes, in my opinion, other than not using type prefixes in the first place.

That said, if you find the type prefixes as useful and don't see them as a maintenance/portability issue, do ignore me; I am only describing my own observations, and basing my advice on what kind of practices I believe lead to most robust and maintainable code.
« Last Edit: October 01, 2019, 01:26:49 am by Nominal Animal »
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 10086
  • Country: us
Re: C word
« Reply #188 on: October 01, 2019, 01:31:37 am »

Much more important than that, is to write comments that describe the programmer intent -- what the code should accomplish --, instead of explaining what the code does.  Learning to write good, useful comments is an invaluable skill, and it is much easier to learn early than late.  Me myself, I'm still working on that.

Comments?  Why do you think they call it code?
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2450
  • Country: us
Re: C word
« Reply #189 on: October 01, 2019, 01:43:25 am »

Much more important than that, is to write comments that describe the programmer intent -- what the code should accomplish --, instead of explaining what the code does.  Learning to write good, useful comments is an invaluable skill, and it is much easier to learn early than late.  Me myself, I'm still working on that.

Comments?  Why do you think they call it code?

Even good comments are code to those that don't know the subject matter. It's like trying to understand medical terminology without being educated in the field.
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: C word
« Reply #190 on: October 01, 2019, 01:44:13 am »

Much more important than that, is to write comments that describe the programmer intent -- what the code should accomplish --, instead of explaining what the code does.  Learning to write good, useful comments is an invaluable skill, and it is much easier to learn early than late.  Me myself, I'm still working on that.

Comments?  Why do you think they call it code?
:P

No code is perfect.  Or even if it is perfect right now, it won't be tomorrow, or a week or a month or a year from now.  Because things change, we need to maintain code; either to fix it if things change enough to break it, or to extend or adapt it to fit our changing needs better.

Code implements algorithms.  If the implementation has a bug, it is easier to find if you have comments explaining what the intent, the underlying algorithm, of the code is.  Compilers ignore comments, but to us humans, they are like waypoints on a map, or sanity checks, that we can use to check the code against our/developer expectations.  Without comments, we must extrapolate the underlying algorithm or approach from the code, which is an added stage where human errors or misunderstandings can occur.

Thus, by writing good comments describing the algorithm or intent behind what the code should accomplish, makes it easier to maintain that code.
 

Offline Gandalf_Sr

  • Super Contributor
  • ***
  • Posts: 1729
  • Country: us
Re: C word
« Reply #191 on: October 01, 2019, 09:41:39 am »
Thanks guys (and girls?).  The insight and examples you have walked me through provide incredibly useful insight into my clunky code writing.

Apologies to the OP who has probably run away to join a monastery by now.
If at first you don't succeed, get a bigger hammer
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: C word
« Reply #192 on: October 01, 2019, 10:33:36 am »

Much more important than that, is to write comments that describe the programmer intent -- what the code should accomplish --, instead of explaining what the code does.  Learning to write good, useful comments is an invaluable skill, and it is much easier to learn early than late.  Me myself, I'm still working on that.

Comments?  Why do you think they call it code?

Do you know the good point of Prologic? You do not have to express a comment to describe your intent, your code is perfectly able to express it in a human form of language.

Ah, Prologic ... it was great, but it's currently of the color of a TV a tuned to a dead channel.

 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 8349
  • Country: fi
    • My home page and email address
Re: C word
« Reply #193 on: October 01, 2019, 05:03:06 pm »
Do you know the good point of Prologic? You do not have to express a comment to describe your intent, your code is perfectly able to express it in a human form of language.
Do you mean Prolog?

Ah, Prologic ... it was great, but it's currently of the color of a TV a tuned to a dead channel.
:o
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: C word
« Reply #194 on: October 01, 2019, 05:40:22 pm »
yup, Pro Logic, aka Prolog; the tool Stood is partially written in Prolog ;D

But Stood costs too much money, so a couple of weeks ago I got my copy of Turbo Prolog v1 and v2 (Borland). It works on a 486 guest-card under RiscOS v4.39; while GNU Prolog on Linux is rather 0xdeadbeaf ... a lot of stuff is broken, and it's easy to crash.

But Turbo Prolog is solid like a stone.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: C word
« Reply #195 on: October 01, 2019, 05:49:50 pm »
Code: [Select]
        dev->resource[0].start = dev->resource[0].end = 0;
(linux kernel, in a driver)

Why do I hate C? Because it allows crazy lines like this.
Are you sure it's correct? Is it a bug? .... not easy to say.
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 8058
  • Country: pl
Re: C word
« Reply #196 on: October 01, 2019, 06:39:03 pm »
I have no idea if it's correct or buggy but it's easy to say what it does :P
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17773
  • Country: fr
Re: C word
« Reply #197 on: October 01, 2019, 06:46:52 pm »
Code: [Select]
        dev->resource[0].start = dev->resource[0].end = 0;
(linux kernel, in a driver)

Why do I hate C? Because it allows crazy lines like this.
Are you sure it's correct? Is it a bug? .... not easy to say.

You don't need to use that construct if you don't want to. Assignments are actually expressions which hold the value of the assignment; that kind of makes sense actually. So that allows this kind of multiple assignement construct. If it doesn't work for you, don't use it.

I admit I very very rarely use this (if ever). One reason is maintainability: it assumes that two lvalues (or more) are to be assigned the same value. Your code may change at some point, where it's not true anymore, and you'll need to split this into two separate assignments. You may forget doing it if the assignments are written this way...

This is really a shortcut that should probably not be used anymore. One of the rationale (as other shortcuts), IMO, was to save screen estate, which was at a premium back in the day. Now we have large screens with huge resolution, but when you only had like 80 columns and 40 lines, shortening everything you could made sense...
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17773
  • Country: fr
Re: C word
« Reply #198 on: October 01, 2019, 07:00:15 pm »
For example, if you consider that space-after-sizeof thing I've suggested, it is not even style issue, but a tool to internalize that particular oddity: sizeof being an operator, and not a function.

I agree with this particular part, although I admit not caring much for sizeof, because it's not a function, but it still "returns" (yield) a value, so writing it like a function doesn't bother me much.
OTOH, I fully agree about all C constructs that are not function calls, such as if, while, for, etc. I ALWAYS put a white space between the keyword and the opening '(', whereas I never when calling a function, so this looks a lot clearer and logical. I've seen code doing the exact opposite of this, which looks insane. The natural way of function calling, if you at least have learned some maths, is "f(x)", not "f (x)". No whitespace, which could be ambiguously seen as an implicit multiplication in maths. Sure C is not maths, but you get the idea.

That said, if you find the type prefixes as useful and don't see them as a maintenance/portability issue, do ignore me; I am only describing my own observations, and basing my advice on what kind of practices I believe lead to most robust and maintainable code.

I indeed do. I'm still not sure about your maintenance points; if I change the type of a variable or parameter to the point that its prefix should change, I'll change the prefix everywhere it needs to. I don't see it as a problem actually. If you change a type, it's likely (at least not unlikely) to have impacts EVERYWHERE it's used, so looking that up is natural. For instance, I'll prefix a pointer with p. If suddenly I change types, and the identifier is NOT a pointer anymore, that's likely to be a major change that needs many other changes anyway.

Now maybe you're thinking of the abused way of using hungarian notation, and taking it too far, which I don't do. Some abusive users of it have actually gone way too far (I remember Microsoft was a heavy user of it, and went a bit too far with it), and coming up with prefixes for almost every possible type definition, even custom ones! This is not at all what I do. I keep it clean and simple, and this way maintenance is absolutely no issue. I'll prefix pointers with p. If a given identifier is not a pointer, it's not prefixed with p. End of story. If I change a function parameter, it was a pointer, and is suddenly not anymore, you'll bet you'll have to change many things, and the prefix will be the least of your problems here... So. I have a small set of rules for prefixing, and stick to it. I avoid going too far.

« Last Edit: October 01, 2019, 07:02:29 pm by SiliconWizard »
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: C word
« Reply #199 on: October 01, 2019, 07:05:57 pm »
You don't need to use that construct if you don't want to.

It was not written by me. That is the point. It was a mistake made by someone who edited the file making a mess without knowing it, and GCC silently accepted it.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf