News for hackers. Stuff that matters.

ben_bradley

Re:Everything I wish I knew when learning C on Monday November 28, 2022 @11:35PM (#33783736)
Spaces are ignored (except to separate things where other syntactical things like * or , aren't present), and * binds to the variable on the right, not the type on the left. I actually got this wrong in an online test, but I screenshotted every question so I could go over them later (! I admit, a dirty trick but I learned things like this from it, though I still did well enough on the test to get the interview).

int*x,y; // x is pointer to int, y is int.

int x,*y; // x is int, y is pointer to int

And the reason I got it wrong on the test is it had been MANY years since I defined more than one variable in a statement (one variable defined per line is wordier but much cleaner), so if I ever knew this rule before, I had forgotten it over time.

I keep wanting to use slash-star comments, but I recall // is comment-to-end-of-line in C99 and later, something picked up from its earlier use in C++.

Oh yeah, C99 has become the de-facto "official" C language, regardless of more recent changes/improvements, as not all newer changes have made it into newer compilers, and most code written since 1999 seems to follow the C99 standard. I recall gcc and many other compilers have some option to specify which standard to use for compiling.

Re:Everything I wish I knew when learning C on Monday November 28, 2022 @10:55PM (#33783517)
I started learning C around when ANSI C came out, and learned much of this in self defense. I'm glad I decided to learn C++ in recent years, it has fixes for so many things (like pass by reference instead of passing pointers, const values can be used to define array sizes though it's better to use vectors anyway, etc.), but that's off topic.

A few things I didn't see mentioned: Add multiple inclusion guards to every header file you write, it saves multiply-defined errors and such:

file mygreatheaderfile.h:

#ifndef MYGREATHEADERFILE_H

#define MYGREATHEADERFILE_H

/* insert usual header file content here /

#endif / #ifndef MYGREATHEADERFILE_H */

Most (all?) compilers have a "don't include this file more than once" preprocessor directive, but from what I've seen they're nonstandard and they vary, but using the above method always works.

If I have a "complete program" with a main function and other functions in one source file, I put main() at the end and put all functions in the order they are called, that way there's no need for function prototypes (except for recursion) as there would be if main() is the first function in the file. None of the C books I've read said you could do this, but when I figured it out I thought yeah, it's just like Pascal and assembly, you have to define something before you use it, but you can make the first occurrence be the function definition and not have to have a separate prototype.

As for naming and capitalizing, as the document said, there's no standard/convention of camelCase vs. snake_case, but all macro names using #define are by convention in ALL_CAPS. That way it's easy to tell a MAX(x, y) macro from a max (x, y) function, and you can eventually learn why never to write such perverse things as MAX (x++, y++). Trace through the expansion to see why (and see why it's better to use a function instead, or in C++ a template): #define MAX(x,y) x>y?x:y

Equals comparison/assignment and if statements: One of the most common and insidious errors in C is accidentally doing an assignment (=) instead of comparison (==). Modern C compilers (the ones with integrated C++ compilers, see below) will give a warning when they see this, but still, if one of these is a constant, put the constant on the left so it will give an ERROR if you accidentally try to assign something to the constant as in if (5 = n) instead of what may feel natural but be wrong (and compile fine with an old compiler!), if (n = 5). There are other gotchas like this, but I can't think of them all, and there's probably too many to post here anyway. I do see "undefined behavior" discussed. Be sure to make backups before running your code.

If you need to do maintenance using some original C compiler for an embedded controller from 30 years ago (or indeed modern C as is still popular in embedded systems), you really need to know all these ins and outs, and I might be convinced to help for an appropriately high hourly amount, but virtually every C compiler nowadays is part of a C++ compiler, and you can do much of this stuff in C++ using better code practices, resulting in fewer bugs.

It's such a common capitalist concept that a word was invented for it: Monetize.
Re:Floor, Ceiling, Bracket on Friday April 16, 2021 @03:58PM (#26838425)
Both math(s) and (almost?) all programming languages have their quirks and inconsistencies. What immediately comes to mind is (a thing I've recently learned) the template syntax of C++ where if you get a single character wrong you get dozens of lines of error messages (there's a code golf on exactly this).

At least with programming, you generally don't see different semantics depending on the value of something! With math, there's sin^2 as in: sin^2 theta + cos^2 theta = 1, which reads the square of the sin of theta, etc. But then there's sin^-1 which means the inverse sine AKA arcsine, and NOT 1 / sine, which would be consistent with previous usage.

Re:Floor, Ceiling, Bracket on Friday April 16, 2021 @03:44PM (#26838279)
And then there is the Hann window function, sometimes called ... "named after Julius von Hann, and sometimes referred to as Hanning, presumably due to its linguistic and formulaic similarities to the Hamming window." Wikipedia, window function