Why do you think a macro is necessary? Outside of things that can only be determined at compilation time, you shouldn't be using #define.
(We have gotten way off topic.)
I am not sure who you are addressing, but I used a macro so you can call printbits() with any data type. To do it without a macro you would either need separate functions for every data type (printintbits(), printfloatbits(), printcharbits(), printdoublebits(), etc.) or you would need to pass a pointer and specify how many bytes to display:
Code:
void printbitsfn(void *p, size_t sz) {
if (!p || !sz) return;
char *v = (char *)p;
for (int ii = 0; ii < sz; ii++;)
for (int jj = CHAR_BIT; jj-->0;)
v[ii] & (1 << jj) ? putchar('1') : putchar('0');
}
Then the usage is:
printbitsfn(&average, sizeof(average));
And you can't call that function directly on a literal. The macro can easily handle all data types up to 64 bits with a much simpler syntax and the ability to handle literals. If you need to print bits for a dense array, or if you have a variable named "__macro_printbits_ii" in scope, then the function is superior though.
Although, if I were doing it with a function I wouldn't directly print the bits, but instead return them in a c string:
Code:
char* getbits(void *p, size_t sz) {
if (!p || !sz) return 0;
int kk = sz * CHAR_BIT;
char *c = malloc(kk + 1);
if (!c) return 0;
char *v = (char *)p;
c[kk] = 0;
for (int ii = sz; ii --> 0;)
for (int jj = 0; jj < CHAR_BIT; jj++)
c[--kk] = v[ii] & (1 << jj) ? '1' : '0';
return c;
}
I think that should work.
I used macros as an illustrative example, not because I thought a macro was necessary.
In other words, after seeing the effect of parens, I was reminded that writing macros can be perilous if they result in an unparenthesized expression.
EDIT
This macro doesn't compile. A 'for' statement can't be enclosed in parens. Only expressions can be enclosed in parens.
It will compile after replacing the first '(' with {, and the last ')' with ;}. Unfortunately, this doesn't make it work. The shifting also needs to be fixed, because the expression added to '0' isn't always just a 0 or 1.
The {} will preclude its use with the comma operator. There are other consequences as well, since the expansion is no longer an expression, but a {} block.
Thanks for checking, that's what I get for writing code while away from a compiler. It should work though if we pull the usual macro trick and wrap it in do{}while(0)
Code:
#define printbits(x) do { \
for(int __macro_printbits_ii = CHAR_BIT * sizeof(x); __macro_printbits_ii --> 0;) \
((x) >> __macro_printbits_ii) & 1 ? putchar('1') : putchar('0'); \
} while(0)
And good catch with the value of the bit-shift expression. I've changed that around to fix it.
Edit: cleaned up functions to (hopefully) work properly with respect to chars being promoted to ints within subexpressions, regardless of sign bits.
Edit 2: updated macro to work with all simple types, even those longer than long long, such as long doubles.