S
Shao Miller
Well here's another possibly curious/interesting use of the ternary
conditional operator.
The 'destplus1_plus_sourceplus3' macro takes two lvalues with any
type.
It creates "scratch space" for a copy of each object. The scratch
space for each is an array of 'char' that is twice the 'sizeof' the
object.
Somewhere within such a scratch space is a position which will be
properly aligned for the type of object, since the 'sizeof' the object
must be a multiple of the alignment of that type. Why? Because
otherwise an array of that type would produce objects that were
improperly aligned. That would be silly.
It calculates the position within the scratch space which is both
[properly aligned] and [a distance away from address 0] which is an
integral multiple of the 'sizeof'.
Pretending that there is an array of a particular object type spanning
from address 0 all the way through our scratch space, it calculates
the index into such an array for the type of object of each operand.
That is, "for what 'index' does '(type *)0 + index' yield the lowest
pointer into our scratch space?"
It copies the values of the operands into.
It performs some extremely trivial (it's an example) arithmetic on
these copies. An interesting note is that:
::: The operations performed are according to the type of the macro's
operands. :::
It copies a result back into the "destination" object.
#include <stddef.h>
#include <stdio.h>
#define TT(x) (1 ? 0 : &(x))
#define destplus1_plus_sourceplus3(dest_, source_) \
do { \
/* Scratch space for copy of dest_ */ \
char dest_copy[sizeof (dest_) * 2]; \
/* Scratch space for copy of source_ */ \
char source_copy[sizeof (source_) * 2]; \
/* Offset of scratch space for copy of dest_ */ \
ptrdiff_t od = dest_copy - (char *)0; \
/* Offset of scratch space for copy of source_ */ \
ptrdiff_t os = source_copy - (char *)0; \
\
/* Evaluate dest_ and note its address */ \
void *dest = &(dest_); \
/* Evaluate source_ and note its address */ \
void *source = &(source_); \
/* Adjust offset for copy of dest_ */ \
od += od % sizeof (dest_); \
/* Adjust offset for copy of source_ */ \
os += os % sizeof (source_); \
/* Adjust offset for copy of dest_ to be an index */ \
od /= sizeof (dest_); \
/* Adjust offset for copy of source_ to be an index */ \
os /= sizeof (source_); \
/* Copy dest_ */ \
memcpy(TT(dest_) + od, dest, sizeof (dest_)); \
/* Copy source_ */ \
memcpy(TT(source_) + os, source, sizeof (source_)); \
\
/* At last, we can now work with our copies */ \
\
/* Increment copy of dest_, according to its type! */ \
TT(dest_)[od]++; \
/* Add 3 to copy of source_, according to its type! */ \
TT(source_)[os] += 3; \
/* Add the copies together and store in copy of dest_ */ \
TT(dest_)[od] += TT(source_)[os]; \
/* Copy back into dest_ */ \
memcpy(dest, TT(dest_) + od, sizeof (dest_)); \
} while (0)
int main(void) {
short s = 2;
int i = 3;
double f = 5.5;
long double Lf = 7.5;
destplus1_plus_sourceplus3(s, i);
destplus1_plus_sourceplus3(f, Lf);
printf("s: %hd ((2 + 1) + (3 + 3))\n", s);
printf("i: %i\n", i);
printf("f: %f ((5.5 + 1) + (7.5 + 3))\n", f);
printf("Lf: %Lf\n", Lf);
return 0;
}
I might expect that some bounds-checking implementations might not
enjoy adding _any_ integer to a null pointer, but at least the code
doesn't _dereference_ a null pointer. I am curious about which
implementations might produce unexpected results from this code for
that reason.
Enjoy (for what it's worth).
- Shao Miller
conditional operator.
The 'destplus1_plus_sourceplus3' macro takes two lvalues with any
type.
It creates "scratch space" for a copy of each object. The scratch
space for each is an array of 'char' that is twice the 'sizeof' the
object.
Somewhere within such a scratch space is a position which will be
properly aligned for the type of object, since the 'sizeof' the object
must be a multiple of the alignment of that type. Why? Because
otherwise an array of that type would produce objects that were
improperly aligned. That would be silly.
It calculates the position within the scratch space which is both
[properly aligned] and [a distance away from address 0] which is an
integral multiple of the 'sizeof'.
Pretending that there is an array of a particular object type spanning
from address 0 all the way through our scratch space, it calculates
the index into such an array for the type of object of each operand.
That is, "for what 'index' does '(type *)0 + index' yield the lowest
pointer into our scratch space?"
It copies the values of the operands into.
It performs some extremely trivial (it's an example) arithmetic on
these copies. An interesting note is that:
::: The operations performed are according to the type of the macro's
operands. :::
It copies a result back into the "destination" object.
#include <stddef.h>
#include <stdio.h>
#define TT(x) (1 ? 0 : &(x))
#define destplus1_plus_sourceplus3(dest_, source_) \
do { \
/* Scratch space for copy of dest_ */ \
char dest_copy[sizeof (dest_) * 2]; \
/* Scratch space for copy of source_ */ \
char source_copy[sizeof (source_) * 2]; \
/* Offset of scratch space for copy of dest_ */ \
ptrdiff_t od = dest_copy - (char *)0; \
/* Offset of scratch space for copy of source_ */ \
ptrdiff_t os = source_copy - (char *)0; \
\
/* Evaluate dest_ and note its address */ \
void *dest = &(dest_); \
/* Evaluate source_ and note its address */ \
void *source = &(source_); \
/* Adjust offset for copy of dest_ */ \
od += od % sizeof (dest_); \
/* Adjust offset for copy of source_ */ \
os += os % sizeof (source_); \
/* Adjust offset for copy of dest_ to be an index */ \
od /= sizeof (dest_); \
/* Adjust offset for copy of source_ to be an index */ \
os /= sizeof (source_); \
/* Copy dest_ */ \
memcpy(TT(dest_) + od, dest, sizeof (dest_)); \
/* Copy source_ */ \
memcpy(TT(source_) + os, source, sizeof (source_)); \
\
/* At last, we can now work with our copies */ \
\
/* Increment copy of dest_, according to its type! */ \
TT(dest_)[od]++; \
/* Add 3 to copy of source_, according to its type! */ \
TT(source_)[os] += 3; \
/* Add the copies together and store in copy of dest_ */ \
TT(dest_)[od] += TT(source_)[os]; \
/* Copy back into dest_ */ \
memcpy(dest, TT(dest_) + od, sizeof (dest_)); \
} while (0)
int main(void) {
short s = 2;
int i = 3;
double f = 5.5;
long double Lf = 7.5;
destplus1_plus_sourceplus3(s, i);
destplus1_plus_sourceplus3(f, Lf);
printf("s: %hd ((2 + 1) + (3 + 3))\n", s);
printf("i: %i\n", i);
printf("f: %f ((5.5 + 1) + (7.5 + 3))\n", f);
printf("Lf: %Lf\n", Lf);
return 0;
}
I might expect that some bounds-checking implementations might not
enjoy adding _any_ integer to a null pointer, but at least the code
doesn't _dereference_ a null pointer. I am curious about which
implementations might produce unexpected results from this code for
that reason.
Enjoy (for what it's worth).
- Shao Miller