The other side effect expression here is the equals operator; once again, this should not be an expression but should just be a statement. Once again this is used (intentionally) mainly for compactness and unintentionally used to create messy bugs. I do find the "yoda" style checks to be aesthetically unpleasing so I'm party of the problem here.
Maybe it's time to add `-Wno-crement-expressions` and `-Wno-assignment-expressions`. `-Wparentheses` gets you part of the way to the second but even the legitimate uses are ugly to my eye.
Aren't there static analyzers in widespread use that would catch these?
void *my_memcpy(void *dst, const void *src, size_t n)
{
const uint8_t *s = src;
uint8_t *d = dst;
for (size_t i = 0; i < n; i += 1) d[i] = s[i];
return dst;
}
int powi(int x, int y)
{
int result = 1;
for (int i = 0; i < y; i += 1) result *= x;
return result;
}
For itoa, I experiment with the comma operator to show the post-increment on the same line, but visibly after. I also move the negation sign block to the absolute value block. void itoa(int n, char s[])
{
int i = 0;
if (n < 0){
n = -n;
s[0] = '-', s += 1; // exclude from reverse
}
do{
s[i] = n % 10 + '0', i += 1;
n /= 10;
}while(n > 0);
s[i] = '\0';
// reverse
for(int j = 0, hi = i / 2; j < hi; j += 1) {
i -= 1;
char swap = s[j];
s[j] = s[i];
s[i] = swap;
}
}
Test code: #include <stdio.h>
#include <stdint.h>
// insert functions
int main(void){
char src[] = "hello";
char dst[10];
my_memcpy(dst, src, sizeof(src));
printf("%s == hello\n", dst);
printf("%d == 27\n", powi(3,3));
itoa(-12345, dst);
printf("%s == -12345\n", dst);
itoa(0, dst);
printf("%s == 0\n", dst);
}If we ban side effects from expressions, we must change the "for" syntax too, because the third "argument" currently is an expression. It should be a statement instead. Let's see...
for (int i=0; i<n; ++i) // old
for (int i=0; i<n; i+=1;) // new
What about the typical 2-variable loop? for (int i=0,j=n; i<j; ++i,--j) // old
for (int i=0,j=n; i<j; {i+=1;j-=1;}) // maybe?
Or we simply forbid all this and force the increment and decrement in the body: for (int i=0,j=n; i<j; ;) {
...
i+=1;
j-=1;
}
This is throwing the baby out with the bathwater!And finally, if the third argument is a statement, would a break or continue be accepted there as well? A nested for? Sure, these are examples of abusing the syntax, but so is using x and ++x in the same expression.
My conclusion is that some constructs are so powerful that they can both simplify our code and make it unreadable. The choice how to use them is ours.