If people can understand the concept of Unions from c/c++ they can understand reductionism. One can use different overlaping data structures to access the same physical locations in memory.
union mix_t
{
long l;
struct
{
short hi;
short lo;
} s;
char c[4];
} mix;
Unfortunately the blog ate my indentations.
Is mix made up of a long, shorts or chars? Silly questions. mix.l, mix.s and mix.c are accessing the same physical memory location.
This is reductionism in a nutshell, it’s talking about the same physical thing using different data types. You can ‘go up’(use big data types) or ‘go down’ use small data types but you are still referring to the same thing.
In conclusion, aspiring rationalists should learn some basic c++.
As a C programmer who hangs out in comp.lang.c, I’m strongly tempted to get out a copy of C99 so that I can tell you precisely where you’re wrong there. But I’ll content myself with pointing out that there is no guarantee that sizeof(long)==2*sizeof(short)==4*sizeof(char), and moreover that even if that did hold, there is still no guarantee that sizeof(struct {short hi; short lo;})==2*sizeof(short) because the struct might have padding—what if ‘short’ were a 16 bit quantity but stored in 32 bit words (perhaps because the arch can only do 32 bit writes, and has decided that short should be an int_fast16_t rather than an int_least16_t), resulting in alignment requirements?
In conclusion, PK should learn some basic C, and forget about the ++. (Old joke: what does C++ mean? Take C, add to it, then use the old version)
EDIT: thanks, paper-machine, and I approve of Markdown’s choice of escape character. Now, if it’ll just let me use \033[1;35m to change the colour...
I don’t see anything wrong with grandparent, assuming a particular architecture. And whenever I used to write c, it was almost always for a particular architecture, usually with inlined assembly. Am I missing something, or are you just trying to make some point about portability regarding a metaphor?
It is a lesson hard-learned over many programmer-years of coding that portability should be acquired as an innate reflex; that whenever you are about to sacrifice portability, you ask yourself “Why am I doing so, are there alternatives, and have I done at least a rudimentary cost/benefit analysis of this decision?”
What you don’t do is throw away portability just because you happen to be using a particular machine right now. This is something quickly learned in comp.lang.c.
Incidentally, a better model than PK’s might be:
typedef struct foo {int i} s;
s f;
Now what is ‘f’? Is it an ‘s’, is it a struct foo, or is it an int? And what about f.i? Both have the same address, casting either’s address to any of the pointer types ‘s *’, ‘struct foo *’ or ‘int *’ is valid; writing
*(int *)&f=1;
does just the same as f.i=1; quite possibly the compiler will generate the same code, because after all, the territory is the same. It’s just that “f.i=1” is a higher-level map, which conveniently abstracts things out.
This is made more explicit by considering struct bar {int a; long b;} t; *(long *)(((char *)&bar)+offsetof(bar, b))=1; // same as bar.b=1
Of course, you could go to all the trouble of computing the offset pointer every time, since that’s what happens on the “quark” (assembly language) level of the territory, but the higher-level ‘struct’ map is cognitively useful.
If people can understand the concept of Unions from c/c++ they can understand reductionism. One can use different overlaping data structures to access the same physical locations in memory.
union mix_t { long l; struct { short hi; short lo; } s; char c[4]; } mix;
Unfortunately the blog ate my indentations.
Is mix made up of a long, shorts or chars? Silly questions. mix.l, mix.s and mix.c are accessing the same physical memory location.
This is reductionism in a nutshell, it’s talking about the same physical thing using different data types. You can ‘go up’(use big data types) or ‘go down’ use small data types but you are still referring to the same thing.
In conclusion, aspiring rationalists should learn some basic c++.
As a C programmer who hangs out in comp.lang.c, I’m strongly tempted to get out a copy of C99 so that I can tell you precisely where you’re wrong there. But I’ll content myself with pointing out that there is no guarantee that sizeof(long)==2*sizeof(short)==4*sizeof(char), and moreover that even if that did hold, there is still no guarantee that sizeof(struct {short hi; short lo;})==2*sizeof(short) because the struct might have padding—what if ‘short’ were a 16 bit quantity but stored in 32 bit words (perhaps because the arch can only do 32 bit writes, and has decided that short should be an int_fast16_t rather than an int_least16_t), resulting in alignment requirements?
In conclusion, PK should learn some basic C, and forget about the ++. (Old joke: what does C++ mean? Take C, add to it, then use the old version)
EDIT: thanks, paper-machine, and I approve of Markdown’s choice of escape character. Now, if it’ll just let me use \033[1;35m to change the colour...
I don’t see anything wrong with grandparent, assuming a particular architecture. And whenever I used to write c, it was almost always for a particular architecture, usually with inlined assembly. Am I missing something, or are you just trying to make some point about portability regarding a metaphor?
It is a lesson hard-learned over many programmer-years of coding that portability should be acquired as an innate reflex; that whenever you are about to sacrifice portability, you ask yourself “Why am I doing so, are there alternatives, and have I done at least a rudimentary cost/benefit analysis of this decision?”
What you don’t do is throw away portability just because you happen to be using a particular machine right now. This is something quickly learned in comp.lang.c.
Incidentally, a better model than PK’s might be:
typedef struct foo {int i} s;
s f;
Now what is ‘f’? Is it an ‘s’, is it a struct foo, or is it an int? And what about f.i? Both have the same address, casting either’s address to any of the pointer types ‘s *’, ‘struct foo *’ or ‘int *’ is valid; writing
*(int *)&f=1;
does just the same as f.i=1; quite possibly the compiler will generate the same code, because after all, the territory is the same. It’s just that “f.i=1” is a higher-level map, which conveniently abstracts things out.
This is made more explicit by considering struct bar {int a; long b;} t; *(long *)(((char *)&bar)+offsetof(bar, b))=1; // same as bar.b=1
Of course, you could go to all the trouble of computing the offset pointer every time, since that’s what happens on the “quark” (assembly language) level of the territory, but the higher-level ‘struct’ map is cognitively useful.
Upvoted for delicious, delicious C.
EDIT: However, you may want to work on the markdown; * is a reserved character ;_;