440,827 Members | 813 Online
Need help? Post your question and get tips & solutions from a community of 440,827 IT Pros & Developers. It's quick & easy.

# problem with macros

 P: n/a Hello, I have the following structure - typedef struct { double x, y, z; }vector; In certain places, I could avoid triplification of code by using an array instead of x, y, z. For eg: typedef struct { double coord[3]; } vector; But this notation does not some people who are going to read my code (physics people). They are used to x, y, z notation for vectors. Also I use long expressions in some places and using coord[index] makes it even more intricate. So I decided to use x, y, z notation but I wrote some macros that could help me in reducing the triplification of code that may happen at some places: #define coord[0] x #define coord[1] y #define coord[2] z I thought this will allow array indexing of the coordinates but instead I got an error "coord redefined" . Why is that ? Aug 1 '08 #1
80 Replies

 P: n/a On 1 Aug 2008 at 20:52, pereges wrote: Hello, I have the following structure - typedef struct { double x, y, z; }vector; In certain places, I could avoid triplification of code by using an array instead of x, y, z. For eg: typedef struct { double coord[3]; } vector; But this notation does not some people who are going to read my code (physics people). They are used to x, y, z notation for vectors. Also I use long expressions in some places and using coord[index] makes it even more intricate. So I decided to use x, y, z notation but I wrote some macros that could help me in reducing the triplification of code that may happen at some places: Almost certainly your compiler won't insert padding between the doubles in the struct, so you can just cast a vector * to double * to treat it as an array. Aug 1 '08 #2

 P: n/a In article , pereges Hello, I have the following structure -typedef struct{ double x, y, z;}vector;In certain places, I could avoid triplification of code by using anarray instead of x, y, z. For eg:typedef struct{ double coord[3];} vector;But this notation does not some people who are going to read my code(physics people). They are used to x, y, z notation for vectors. AlsoI use long expressions in some places and using coord[index] makes iteven more intricate. So I decided to use x, y, z notation but I wrotesome macros that could help me in reducing the triplification of codethat may happen at some places:#define coord[0] x#define coord[1] y#define coord[2] zI thought this will allow array indexing of the coordinates butinstead I got an error "coord redefined" . Why is that ? Because macros can't be in "array form" and instead what you've done is #define coord three times :) I can probably imagine the triplication of code you're referring to, but what the hey, before looking at solutions, can you show an example of the two ways you're talking about, and what you see is their respective pros and cons? -- Greg Comeau / 4.3.10.1 with C++0xisms now in beta! Comeau C/C++ ONLINE == http://www.comeaucomputing.com/tryitout World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90. Comeau C/C++ with Dinkumware's Libraries... Have you tried it? Aug 1 '08 #3

 P: n/a In article , pereges #define coord[0] x Try #define x coord[0] -- "After all, what problems has intellectualism ever solved?" -- Robert Gilman Aug 1 '08 #4

 P: n/a pereges wrote: Hello, I have the following structure - typedef struct { double x, y, z; }vector; In certain places, I could avoid triplification of code by using an array instead of x, y, z. For eg: typedef struct { double coord[3]; } vector; But this notation does not some people who are going to read my code (physics people). They are used to x, y, z notation for vectors. Also I use long expressions in some places and using coord[index] makes it even more intricate. So I decided to use x, y, z notation but I wrote some macros that could help me in reducing the triplification of code that may happen at some places: #define coord[0] x #define coord[1] y #define coord[2] z I thought this will allow array indexing of the coordinates but instead I got an error "coord redefined" . Why is that ? Because `coord[0]' and the rest are not valid identifiers for macros (or for anything else, either). `coord[0]' is a sequence of four tokens (formally "pp-tokens"): `coord', `[', `0', and `]', and a macro name must be a single token -- more, it must be a single token that is a valid identifier. You could do things the other way around: #define x coord[0] #define y coord[1] #define z coord[2] ... norm = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z); where macro replacement transforms the final line to norm = sqrt(vec.coord[0] * vec.coord[0] + vec.coord[1] * vec.coord[1] + vec.coord[2] * vec.coord[2]); However, I wouldn't recommend this. The preprocessor will replace every `x', `y', and `z' it can find, even in unsuitable contexts: double x = (vec1.x + vec2.x) * 0.5; becomes double coord[0] = (vec1.coord[0] + vec2.coord[0]) * 0.5; .... and this is likely to create confusion, in addition to the compile-time diagnostic message. It is tempting, just as many sins are tempting, to define the struct with three elements x,y,z and then pretend it's really an array when you want to loop over them: vector vec = ...; int i; /* Find the opposite vector: */ for (i = 0; i < 3; ++i) *(&vec.x + i) *= -1; This may even work as intended in a lot of situations, but since it sneaks behind the compiler's back to modify vec.y and vec.z without ever mentioning them, an optimizer might mistakenly think they aren't being modified and this could lead to chaos. Maybe not today, but when your compiler gets smarter at the next release ... Just how much "triplification" are you trying to avoid, anyhow? -- Er*********@sun.com Aug 1 '08 #5

 P: n/a "pereges"

 P: n/a pereges said: Hello, I have the following structure - typedef struct { double x, y, z; }vector; In certain places, I could avoid triplification of code by using an array instead of x, y, z. For eg: typedef struct { double coord[3]; } vector; But this notation does not some people who are going to read my code (physics people). They are used to x, y, z notation for vectors. Also I use long expressions in some places and using coord[index] makes it even more intricate. So I decided to use x, y, z notation but I wrote some macros that could help me in reducing the triplification of code that may happen at some places: #define coord[0] x #define coord[1] y #define coord[2] z I thought this will allow array indexing of the coordinates but instead I got an error "coord redefined" . Why is that ? Your question has already been answered, but I have a suggestion for you: #define X 0 #define Y 1 #define Z 2 If your physicist can't understand coord[X] to mean the X coordinate, then he's probably not much of a physicist. -- Richard Heathfield Email: -http://www. +rjh@ Google users: "Usenet is a strange place" - dmr 29 July 1999 Aug 1 '08 #7

 P: n/a Bartc wrote: ) I tried this: ) ) typedef struct ) { ) union { ) struct {double x, y, z;}; ) double coord[3]; ) }; ) ) }vector; ) ) This allows you to access the vector as .x .y .z or as .coord[0] .coord[1] ) .coord[2]. No macros needed. ) ) However you need a compiler that allows anonymous unions and structs. And one where nothing bad happens as a result of the undefined behaviour you just invoked. SaSW, Willem -- Disclaimer: I am in no way responsible for any of the statements made in the above text. For all I know I might be drugged or something.. No I'm not paranoid. You all think I'm paranoid, don't you ! #EOT Aug 1 '08 #8

 P: n/a Eric Sosman Hello, I have the following structure -typedef struct{ double x, y, z;}vector;In certain places, I could avoid triplification of code by using anarray instead of x, y, z. For eg:typedef struct{ double coord[3];} vector;But this notation does not some people who are going to read my code(physics people). They are used to x, y, z notation for vectors. AlsoI use long expressions in some places and using coord[index] makes iteven more intricate. So I decided to use x, y, z notation but I wrotesome macros that could help me in reducing the triplification of codethat may happen at some places:#define coord[0] x#define coord[1] y#define coord[2] zI thought this will allow array indexing of the coordinates butinstead I got an error "coord redefined" . Why is that ? Because `coord[0]' and the rest are not valid identifiers for macros (or for anything else, either). `coord[0]' is a sequence of four tokens (formally "pp-tokens"): `coord', `[', `0', and `]', and a macro name must be a single token -- more, it must be a single token that is a valid identifier. You could do things the other way around: #define x coord[0] #define y coord[1] #define z coord[2] ... norm = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z); where macro replacement transforms the final line to norm = sqrt(vec.coord[0] * vec.coord[0] + vec.coord[1] * vec.coord[1] + vec.coord[2] * vec.coord[2]); However, I wouldn't recommend this. The preprocessor will replace every `x', `y', and `z' it can find, even in unsuitable contexts: double x = (vec1.x + vec2.x) * 0.5; becomes double coord[0] = (vec1.coord[0] + vec2.coord[0]) * 0.5; ... and this is likely to create confusion, in addition to the compile-time diagnostic message. [...] A possible way to avoid this potential problem is to take advantage of the convention that macro names are (usually) in all-caps. For example: typedef struct { double coord[3]; } vector; #define X coord[0] #define Y coord[1] #define Z coord[2] ... double x = (vec1.X + vec2.X) * 0.5; Just make sure not to use the names X, Y, and Z for anything else. You can use still x, y, and z for other things (if you must). -- Keith Thompson (The_Other_Keith) ks***@mib.org Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Aug 1 '08 #9

 P: n/a Richard Heathfield Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Aug 1 '08 #10

 P: n/a Keith Thompson said: A possible way to avoid this potential problem is to take advantage of the convention that macro names are (usually) in all-caps. For example: typedef struct { double coord[3]; } vector; #define X coord[0] #define Y coord[1] #define Z coord[2] ... double x = (vec1.X + vec2.X) * 0.5; Just make sure not to use the names X, Y, and Z for anything else. You can use still x, y, and z for other things (if you must). And another way to avoid this whole mess is not to use macros at all! typedef struct { double *coord[3]; double x; double y; double z; } vector; although this does involve some setup for every vector used: void vector_initialise(vector *p) { p->coord[0] = &p->x; p->coord[1] = &p->y; p->coord[2] = &p->z; } and it means that, in your array processing, you have to deref: for(dim = 0; dim < 2; dim++) { dist += *p->coord[dim] * *p->coord[dim]; } Whether you consider this game to be worth the candle is obviously up to you, but it's a technique I have found useful on occasion. -- Richard Heathfield Email: -http://www. +rjh@ Google users: "Usenet is a strange place" - dmr 29 July 1999 Aug 1 '08 #11

 P: n/a On 1 Aug 2008 at 22:15, Richard Heathfield wrote: typedef struct { double *coord[3]; double x; double y; double z; } vector; although this does involve some setup for every vector used: void vector_initialise(vector *p) { p->coord[0] = &p->x; p->coord[1] = &p->y; p->coord[2] = &p->z; } Wonderful! Time and again Heathfield has shown us that he has a casual disregard for gross inefficiencies in his programming, but this takes the biscuit. The OP explicitly says his main aim is to avoid triplication, so Heathfield proposes a maintenance nightmare that involves keeping triplicate copies of data in sync at all times. Unbelievable. Once again, the solution is very simple: just cast vector* to double*. Aug 1 '08 #12

 P: n/a On Aug 1, 3:52*pm, pereges

 P: n/a "Antoninus Twink" typedef struct{ double *coord[3]; double x; double y; double z;} vector;although this does involve some setup for every vector used:void vector_initialise(vector *p){ p->coord[0] = &p->x; p->coord[1] = &p->y; p->coord[2] = &p->z;} Wonderful! Time and again Heathfield has shown us that he has a casual disregard for gross inefficiencies in his programming, but this takes the biscuit. The OP explicitly says his main aim is to avoid triplication, so Heathfield proposes a maintenance nightmare that involves keeping triplicate copies of data in sync at all times. Unbelievable. Once again, the solution is very simple: just cast vector* to double*. For this to work the fields x,y,z need to be stored in memory in the same way as three consecutive array elements. Apparently there are machines around where this may not be true. I think this was the objection to my idea. -- Bartc Aug 1 '08 #14

 P: n/a On 1 Aug 2008 at 22:54, Bartc wrote: >Once again, the solution is very simple: just cast vector* to double*. For this to work the fields x,y,z need to be stored in memory in the same way as three consecutive array elements. Apparently there are machines around where this may not be true. I think this was the objection to my idea. I suspect these machines exist only in the minds of the "regulars". On most modern hardware, doubles will be 64-bit aligned and a struct with three double fields will not be padded. The OP can double-check this if necessary, and if by some freak chance it does turn out to be a problem, his compiler probably has a way to let him forced no structure padding, e.g. in gcc __attribute__ ((__packed__)). Aug 1 '08 #15

 P: n/a ro***********@yahoo.com wrote: > While heresy around here, if you're actually writing C++ (or can), getters and setters named x, y and z will solve the problem nicely. If you were using C++, you probably wouldn't care about the internal representation! -- Ian Collins. Aug 1 '08 #16

 P: n/a "Bartc" >Once again, the solution is very simple: just cast vector* to double*. For this to work the fields x,y,z need to be stored in memory in the same way as three consecutive array elements. Apparently there are machines around where this may not be true. I think this was the objection to my idea. The OP can guard against that by checking that offsetof(struct vector, z) == 2 * sizeof(double) but I favour making it an array defining an enum to index it. Of course you then have a redundant member name that you have to keep writing, so there is some merit in at least considering: enum { X = 0, Y = 1, Z = 2, Dimensions = 3 }; typedef double vector[Dimensions]; You can't pass one by value to a function, of course, but then I doubt that matters for this application. The code is quite readable this way: vector norm; norm[Z] = norm[X] + norm[Y]; -- Ben. Aug 2 '08 #17

 P: n/a In article , Antoninus Twink On 1 Aug 2008 at 22:54, Bartc wrote: >>Once again, the solution is very simple: just cast vector* to double*. >On most modern hardware, doubles will be 64-bit aligned and a structwith three double fields will not be padded. It isn't uncommon for doubles to be 32 bit aligned, same as float. -- "The quirks and arbitrariness we observe force us to the conclusion that ours is not the only universe." -- Walter Kistler Aug 2 '08 #18

 P: n/a Ian Collins said: ro***********@yahoo.com wrote: >>While heresy around here, if you're actually writing C++ (or can),getters and setters named x, y and z will solve the problem nicely. If you were using C++, you probably wouldn't care about the internal representation! You would if you were reading the code, though, surely? The OP said: "But this notation does not [suit? meet with the approval of?] some people who are going to read my code (physics people)." It is not unreasonable to suppose that they might need to read the class code (in a C++ version of the program), and thus /will/ (or at least may) care about the internal representation. -- Richard Heathfield Email: -http://www. +rjh@ Google users: "Usenet is a strange place" - dmr 29 July 1999 Aug 2 '08 #19

 P: n/a Richard Heathfield wrote: Ian Collins said: >ro***********@yahoo.com wrote: >>While heresy around here, if you're actually writing C++ (or can),getters and setters named x, y and z will solve the problem nicely. If you were using C++, you probably wouldn't care about the internalrepresentation! You would if you were reading the code, though, surely? That depends how the code was written. In C++ a vector could be written as a black box to the user, all operations on the vector being defined as members. The OP said: "But this notation does not [suit? meet with the approval of?] some people who are going to read my code (physics people)." Possibly because you have to work at a lower level in C. It is not unreasonable to suppose that they might need to read the class code (in a C++ version of the program), and thus /will/ (or at least may) care about the internal representation. I guess being "physics people" they might want to mix the code with Fortran :) -- Ian Collins. Aug 2 '08 #20

 P: n/a ro******@ibd.nrc-cnrc.gc.ca (Walter Roberson) writes: [...] It isn't uncommon for doubles to be 32 bit aligned, same as float. It's not possible for any type to have an alignment requirement larger than its size. An array of any type cannot have gaps between the elements. For a structure all of whose members are of the same type, a compiler is *allowed* to insert padding between the members, but I can think of no good reason for it to do so (though it may well have a reason to insert padding at the end). Nevertheless, I personally prefer not to depend on this kind of thing, especially when there are other solutions. And if for some reason I decided to depend on this, I'd add a check so the program aborts quickly in the unlikely event that there *are* gaps between the members. -- Keith Thompson (The_Other_Keith) ks***@mib.org Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Aug 2 '08 #21

 P: n/a "Richard Heathfield" Your question has already been answered, but I have a suggestion for you: #define X 0 #define Y 1 #define Z 2 If your physicist can't understand coord[X] to mean the X coordinate, then he's probably not much of a physicist. It's not a bad idea. The problem is that a less clever person, lets say a C programmer, might look at that and say "Hummm, X is some sort of variable that iterates over a coordinate set. But I don't see it in scope. What on Earth is going on here?" -- Free games and programming goodies. http://www.personal.leeds.ac.uk/~bgy1mm Aug 2 '08 #22

 P: n/a Well triplification of code does happen and it makes the code look ugly. I can't pick out a specific example from my project but usually it happens when you want something to be done with only one coordinate of vector and not all. For eg. in my kdtree building module, I have to find the median of the vertices(vectors) along x, y or z coordinates based on the value of a flag called splitplane. This splitplane may take values 0, 1, 2 (0 means split along x, 1 means split along y, 2 means split along z). If this notation was used - typedef struct { double coord[3]; }vector; vector v; Now, when I find to find out median of many such vectors along some axis given by splitplane flag, I simply need to specify v.coord[splitplane] to the median finding algorithm whereas if this notation is followed - typedef struct { double x, y, z; }vector; vector v; I have to do something like below : if (splitplane == 0) { /* Find median along x */ } if (splitplane == 1) { /* Find median along y */ } if (splitplane == 2) { /* Find median along z */ } This is what I mean by "triplification". Here, the logic behind finding the median is same but it will be repeated thrice. Anyway, I came up with another solution and that is to use a vector iterator function like below : double vector_iterator(vector v, int axis) { if (axis == 0) { return (v.x); } if (axis == 1) { return (v.y); } if (axis == 2) { return (v.z); } } This will reduce some work. What do you think ? Aug 2 '08 #23

 P: n/a "pereges"

 P: n/a On Aug 2, 5:02 pm, "Bartc" typedef struct { double x, y, z; }vector; double *vector_iterator(vector *v, int axis) { switch (axis) { case 0: return (&v->x); case 1: return (&v->y); case 2: return (&v->z); } } int main(void) { vector v; v.x = 5; v.y = 3; v.z = 2; *(vector_iterator(&v, 0)) = 3; /* Note this */ printf("%f", v.x); return 0; } This is fine with my compiler (Output is 3.000000), but I'm unsure about function call on the left side of = operator (lvalue ?) Aug 2 '08 #25

 P: n/a pereges Anyway, I came up with another solution and that is to use a vector iterator function like below : double vector_iterator(vector v, int axis) { if (axis == 0) { return (v.x); } if (axis == 1) { return (v.y); } if (axis == 2) { return (v.z); } } This will reduce some work. What do you think ? There is an old programming rule "pass data to functions, not control" which this function violates (somewhat). If you keep your vectors as structs (and I've suggested an alternative elsewhere) then I would write any functions that need to something with programmatically selected members like this: typedef double (*selector)(vector *); inline double get_x(vector *vp) { return vp->x; } inline double get_y(vector *vp) { return vp->y; } inline double get_z(vector *vp) { return vp->z; } double average_of(vector *v, size_t n, selector axis) { double sum = 0; for (size_t i = 0; i < n; i++) sum += axis(&v[i]); return sum / n; } Obviously, if you need numerical control you can have the selectors in an array: selector axes[] = { get_x, get_y, get_z }; .... average_of(my_vec_array, axes[i]); -- Ben. Aug 2 '08 #26

 P: n/a In article , Antoninus Twink On 1 Aug 2008 at 22:15, Richard Heathfield wrote: >typedef struct{ double *coord[3]; double x; double y; double z;} vector;although this does involve some setup for every vector used:void vector_initialise(vector *p){ p->coord[0] = &p->x; p->coord[1] = &p->y; p->coord[2] = &p->z;} Wonderful!Time and again Heathfield has shown us that he has a casual disregardfor gross inefficiencies in his programming, but this takes the biscuit.The OP explicitly says his main aim is to avoid triplication, soHeathfield proposes a maintenance nightmare that involves keepingtriplicate copies of data in sync at all times. Unbelievable. Let's assume this is so (I'm not saying it is, just to assume so)... >Once again, the solution is very simple: just cast vector* to double*. .... the problem is that your way makes some assumptions (which I seem to recall you clearly stated when you posted it about padding, or not, in the struct), however, that is also a maintenance nightmare, since as you noted, there may or may not be padding. And on machines where there is, it won't even work. How many machines is that in popular use? Dunno, probably not many. But it doesn't negate your point :) -- Greg Comeau / 4.3.10.1 with C++0xisms now in beta! Comeau C/C++ ONLINE == http://www.comeaucomputing.com/tryitout World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90. Comeau C/C++ with Dinkumware's Libraries... Have you tried it? Aug 2 '08 #27

 P: n/a "Malcolm McLean" Your question has already been answered, but I have a suggestion for you:#define X 0#define Y 1#define Z 2If your physicist can't understand coord[X] to mean the X coordinate, thenhe's probably not much of a physicist. It's not a bad idea. The problem is that a less clever person, lets say a C programmer, might look at that and say "Hummm, X is some sort of variable that iterates over a coordinate set. But I don't see it in scope. What on Earth is going on here?" A C programmer is more likely to assume, correctly, that X is likely to be a macro because its name is in all-caps. -- Keith Thompson (The_Other_Keith) ks***@mib.org Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Aug 2 '08 #28

 P: n/a On 2 Aug 2008 at 16:38, Greg Comeau wrote: Antoninus Twink >On 1 Aug 2008 at 22:15, Richard Heathfield wrote: >>typedef struct{ double *coord[3]; double x; double y; double z;} vector;void vector_initialise(vector *p){ p->coord[0] = &p->x; p->coord[1] = &p->y; p->coord[2] = &p->z;} The OP explicitly says his main aim is to avoid triplication, soHeathfield proposes a maintenance nightmare that involves keepingtriplicate copies of data in sync at all times. Unbelievable. Let's assume this is so (I'm not saying it is, just to assume so)... Oops, yes, good spot - I'd scanned Heathfield's code too quickly. So in fact you only need to set it up once (which would be fine in a language with ctors like C++ but is annoying in C), but then you need an ugly extra level of indirection every time you want to access it as an array. Still yuck. Aug 2 '08 #29

 P: n/a Greg Comeau said: In article , Antoninus Twink >On 1 Aug 2008 at 22:15, Richard Heathfield wrote: >>typedef struct{ double *coord[3]; double x; double y; double z;} vector;although this does involve some setup for every vector used:void vector_initialise(vector *p){ p->coord[0] = &p->x; p->coord[1] = &p->y; p->coord[2] = &p->z;} Wonderful!Time and again Heathfield has shown us that he has a casual disregardfor gross inefficiencies in his programming, but this takes the biscuit.The OP explicitly says his main aim is to avoid triplication, soHeathfield proposes a maintenance nightmare that involves keepingtriplicate copies of data in sync at all times. Unbelievable. Let's assume this is so No, let's not, because he's wrong. (I'm not saying it is, just to assume so)... I understand why it is sometimes useful to make questionable assumptions (for example, it's a sine qua non in an r.a.a. proof), but I see no value in it here. He's simply wrong. There is no maintenance nightmare, just a small set-up cost. There is no need to keep triplicate copies of data in sync at all times, since my proposed method doesn't make any copies of the data whatsoever. It seems pretty clear to me that the guy just can't read clearly or think objectively... >>Once again, the solution is very simple: just cast vector* to double*. ....and really really sucks at C. ... the problem is that your way makes some assumptions (which I seem to recall you clearly stated when you posted it about padding, or not, in the struct), however, that is also a maintenance nightmare, since as you noted, there may or may not be padding. And on machines where there is, it won't even work. How many machines is that in popular use? Dunno, probably not many. But it doesn't negate your point :) His point, such as it is, is negated by the fact that it isn't true, and his counter-point is negated by the fact that it breaches the rules of the language. -- Richard Heathfield Email: -http://www. +rjh@ Google users: "Usenet is a strange place" - dmr 29 July 1999 Aug 2 '08 #30

 P: n/a On 2 Aug 2008 at 17:04, Keith Thompson wrote: "Malcolm McLean" It's not a bad idea. The problem is that a less clever person, letssay a C programmer, might look at that and say "Hummm, X is some sortof variable that iterates over a coordinate set. But I don't see it inscope. What on Earth is going on here?" A C programmer is more likely to assume, correctly, that X is likely to be a macro because its name is in all-caps. That would be true if the name was more than one character long. Aug 2 '08 #31

 P: n/a In article , Antoninus Twink On 2 Aug 2008 at 16:38, Greg Comeau wrote: >Antoninus Twink >>On 1 Aug 2008 at 22:15, Richard Heathfield wrote:typedef struct{ double *coord[3]; double x; double y; double z;} vector;void vector_initialise(vector *p){ p->coord[0] = &p->x; p->coord[1] = &p->y; p->coord[2] = &p->z;}The OP explicitly says his main aim is to avoid triplication, soHeathfield proposes a maintenance nightmare that involves keepingtriplicate copies of data in sync at all times. Unbelievable. Let's assume this is so (I'm not saying it is, just to assume so)... Oops, yes, good spot - I'd scanned Heathfield's code too quickly. So infact you only need to set it up once (which would be fine in a languagewith ctors like C++ but is annoying in C), but then you need an uglyextra level of indirection every time you want to access it as an array.Still yuck. Well, the machinery IS interesting, and sometimes that is necessary. For better and for worse. I believe that OP finally posted some more about the intent of the original query, so I guess we'll see more about which solution set seems to make the most sense now. -- Greg Comeau / 4.3.10.1 with C++0xisms now in beta! Comeau C/C++ ONLINE == http://www.comeaucomputing.com/tryitout World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90. Comeau C/C++ with Dinkumware's Libraries... Have you tried it? Aug 2 '08 #32

 P: n/a On Fri, 01 Aug 2008 21:34:34 GMT, "Bartc" "pereges" Hello, I have the following structure -typedef struct{ double x, y, z;}vector;In certain places, I could avoid triplification of code by using anarray instead of x, y, z. For eg:typedef struct{ double coord[3];} vector; I tried this:typedef struct{ union { struct {double x, y, z;}; double coord[3]; };}vector;This allows you to access the vector as .x .y .z or as .coord[0] .coord[1].coord[2]. No macros needed.However you need a compiler that allows anonymous unions and structs. And one that promises not to insert padding. coord[0] is guaranteed to overlay x but the same is not true for the remaining members. -- Remove del for email Aug 2 '08 #33

 P: n/a On Aug 2, 5:29 pm, pereges typedef struct { double x, y, z; }vector; double *vector_iterator(vector *v, int axis) { switch (axis) { case 0: return (&v->x); case 1: return (&v->y); case 2: return (&v->z); } } int main(void) { vector v; v.x = 5; v.y = 3; v.z = 2; *(vector_iterator(&v, 0)) = 3; /* Note this */ printf("%f", v.x); return 0; } This is fine with my compiler (Output is 3.000000), but I'm unsure about function call on the left side of = operator (lvalue ?) By the way, with this code I get a warning : \$ gcc -W -Wall -ansi -pedantic -O2 foo.c foo.c: In function `vector_iterator': foo.c:18: warning: control reaches end of non-void function I actually got this warning in many other programs when there was no return value specified at the end of the function. I could return NULL at the end of course(and then use assert before you store value at the address), but the control will never reach that stage unless the precondition within the function are not satisfied. I don't know if I should absolutely get rid of this warning. Aug 2 '08 #34

 P: n/a pereges wrote: On Aug 2, 5:29 pm, pereges On Aug 2, 5:02 pm, "Bartc" typedef struct{ double x, y, z;}vector;double *vector_iterator(vector *v, int axis){ switch (axis) { case 0: return (&v->x); case 1: return (&v->y); case 2: return (&v->z); }}int main(void){ vector v; v.x = 5; v.y = 3; v.z = 2; *(vector_iterator(&v, 0)) = 3; /* Note this */ printf("%f", v.x); return 0;}This is fine with my compiler (Output is 3.000000), but I'm unsureabout function call on the left side of = operator (lvalue ?) By the way, with this code I get a warning : \$ gcc -W -Wall -ansi -pedantic -O2 foo.c foo.c: In function `vector_iterator': foo.c:18: warning: control reaches end of non-void function I actually got this warning in many other programs when there was no return value specified at the end of the function. When control reaches the terminating brace of a non-void function then an indeterminate value (i.e., garbage) is returned to the caller. You should always return a sensible value for all non-void functions. If you do not want to return any value from a function just declare that function as returning void. For the specific function you might want to include a default case for invalid parameter values. This could return NULL. Aug 2 '08 #35

 P: n/a "Richard Heathfield" In article ,Antoninus Twink >>On 1 Aug 2008 at 22:15, Richard Heathfield wrote:typedef struct{ double *coord[3]; double x; double y; double z;} vector;although this does involve some setup for every vector used:void vector_initialise(vector *p){ p->coord[0] = &p->x; p->coord[1] = &p->y; p->coord[2] = &p->z;}Wonderful!Time and again Heathfield has shown us that he has a casual disregardfor gross inefficiencies in his programming, but this takes the biscuit.The OP explicitly says his main aim is to avoid triplication, soHeathfield proposes a maintenance nightmare that involves keepingtriplicate copies of data in sync at all times. Unbelievable. Let's assume this is so No, let's not, because he's wrong. >(I'm not saying it is, just to assume so)... I understand why it is sometimes useful to make questionable assumptions (for example, it's a sine qua non in an r.a.a. proof), but I see no value in it here. He's simply wrong. There is no maintenance nightmare, just a small set-up cost. There is no need to keep triplicate copies of data in sync at all times, since my proposed method doesn't make any copies of the data whatsoever. As I understand it, you're adding 3 pointers to each struct containing x,y,z doubles, and the pointers are set up to point to each of the x,y,z fields. Apart the inconvenience and extra space and extra dereferencing, I can see this causing problems when such a struct is passed by value to a function, or copied by assignment to another struct: the pointers will point to the fields in the original struct, not the copy. -- Bartc Aug 2 '08 #36

 P: n/a Bartc said: As I understand it, you're adding 3 pointers to each struct containing x,y,z doubles, and the pointers are set up to point to each of the x,y,z fields. Right. Apart the inconvenience and extra space and extra dereferencing, Right again. There ain't no such thing as a free lunch. Perhaps there's a better approach that will solve the OP's problem, but I haven't seen it yet. Any suggestions? I can see this causing problems when such a struct is passed by value to a function, or copied by assignment to another struct: the pointers will point to the fields in the original struct, not the copy. Right again again. In practice, the first of these is easily avoided simply by avoiding passing structs by value, and many people already avoid this for other good reasons. The second isn't a problem if you use a "deep copy" technique rather than simple assignment. Alternatively, you can do your pass-by-value or assignment if you insist, provided that you remember to call, immediately afterwards, the pointer initialisation routine that I supplied. Now, I'm perfectly prepared to accept that this isn't an ideal solution, and I'm certainly prepared to accept that someone may come up with a better idea that meets the OP's needs better whilst remaining correct C. But I haven't yet seen anyone post such an idea. -- Richard Heathfield Email: -http://www. +rjh@ Google users: "Usenet is a strange place" - dmr 29 July 1999 Aug 2 '08 #37

 P: n/a pereges #include typedef struct{ double x, y, z;}vector;double *vector_iterator(vector *v, int axis){ switch (axis) { case 0: return (&v->x); case 1: return (&v->y); case 2: return (&v->z); }} [...] By the way, with this code I get a warning : \$ gcc -W -Wall -ansi -pedantic -O2 foo.c foo.c: In function `vector_iterator': foo.c:18: warning: control reaches end of non-void function I actually got this warning in many other programs when there was no return value specified at the end of the function. I could return NULL at the end of course(and then use assert before you store value at the address), but the control will never reach that stage unless the precondition within the function are not satisfied. I don't know if I should absolutely get rid of this warning. You can get rid of the warning by adding a default case: ... default: return NULL; You're getting the warning because the compiler has no way of knowing that the value of axis will always be in the range [0, 2]. Incidentally, this might be a good place for an assert(), something like: double *vector_iterator(vector *v, int axis) { assert(axis >= 0 && axis <= 2); switch (axis) { case 0: return &v->x; case 1: return &v->y; case 2: return &v->z; default: return NULL; } } The assumption is that an axis value outside that range is a programming error, not a data error. If there's a possibility of the axis value being derived from user or file input, you should handle it as a data error, not using assert(). -- Keith Thompson (The_Other_Keith) ks***@mib.org Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Aug 2 '08 #38

 P: n/a In article <44**********************************@v1g2000pra.g ooglegroups.com> pereges ... usually [the code duplication] happens when you want somethingto be done with only one coordinate of vector and not all. For eg.in my kdtree building module, I have to find the median of thevertices(vectors) along x, y or z coordinates based on the valueof a flag called splitplane. This splitplane may take values 0, 1,2 (0 means split along x, 1 means split along y, 2 means splitalong z). If this notation was used - typedef struct { double coord[3]; } vector;... I simply need to specify v.coord[splitplane] ... whereas if thisnotation is followed - typedef struct { double x, y, z; } vector;I have to do something like below : if (splitplane == 0) { /* Find median along x */ } if (splitplane == 1) { /* Find median along y */ } if (splitplane == 2) { /* Find median along z */ }This is what I mean by "triplification". Here, the logic behindfinding the median is same but it will be repeated thrice. Elsethread, others have suggested various approaches. Here is one more that is a variant of the pointer-to-element version. It is not very pretty, but -- modulo errors (this code is untested) -- is guaranteed to work, and *may* have a lower runtime cost than calling a function to find &vecp->x, &vecp->y, or &vecp->z. [begin contents of vector.h] /* Vector type, including its element-type. */ typedef double Vector_elt_type; /* * optionally, you might also includ * typedef struct vector Vector_type; * but I prefer to use the word "struct" for a type-name, except * in cases where it is guaranteed to be an alias for a scalar * type (as with Vector_elt_type, which is one of float, double, * or long double). * * (Think of the "struct" keyword as a funny way to spell the * word "type".) */ struct vector { Vector_elt_type x, y, z; }; /* Vector "plane selector" numbers. */ enum { VECTOR_X = 0, VECTOR_Y = 1, VECTOR_Z = 2 }; /* * Note that these are byte offsets, so that they will work * even if the "vector" struct is augmented with additional * fields before, between, and/or after the three elements * we care about, and regardless of any padding a compiler might * use. */ extern const size_t vector_field_offsets[]; /* * Given a pointer to a vector, pick the X, Y, or Z element based * on the plane number, which must be one of VECTOR_X, VECTOR_Y, * or VECTOR_Z. */ #define VECTOR_TO_ELT(vecp, plane) \ ((Vector_elt_type *)((char *)(vecp) + vector_field_offsets[plane])) [end of vector.h extract -- there might be more in there, e.g., prototypes for functions in vector.c] [begin contents of vector.c] #include "vector.h" /* * The initializers here assume that VECTOR_X is 0, * VECTOR_Y is 1, and VECTOR_Z is 2. We could check this * with a COMPILE_TIME_ASSERT macro (google for it), but * here I do not bother. */ const size_t vector_field_offsets[] = { offsetof(struct vector, x), offsetof(struct vector, y), offsetof(struct vector, z), }; [end contents of vector.c, though in practice there would be more code] [begin contents of some vector-using C code] #include #include #include "vector.h" /* some sort of median finding operation: */ void median_op(struct vector *vector_set, size_t nvectors, int plane) { size_t i; Vector_elt_type *p; ... other variables as needed ... /* * It is a programmer error to call this function with * a plane that is not one of the three specified vector * plane numbers. */ assert(plane == VECTOR_X || plane == VECTOR_Y || plane == VECTOR_Z); for (i = 0; i < nvectors; i++) { p = VECTOR_TO_ELT(&vector_set[i], plane); ... work with *p as needed to find median ... } } -- In-Real-Life: Chris Torek, Wind River Systems Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603 email: gmail (figure it out) http://web.torek.net/torek/index.html Aug 3 '08 #39

 P: n/a pereges said: ... this notation does not [suit?] some people who are going to read my code (physics people). They are used to x, y, z notation for vectors. Physicists understand vectors as n-tuples perfectly well. They even understand zero indexing, probably better than most programmers! Indeed, I think you're more likely to find the physicist asking why you bother treating the vectors as xyz when you should be treating them more generally as x0, x1, x2, etc... It's typically only the dumb computer programmers who need to 'visualise' the vector manipulations in terms of 2d or 3d. So who are you really doing this for? ;) Richard Heathfield

 P: n/a > >#define x coord[0] That would work, but shall we count the ways it would blow up in your face? Frankly, I don't think there's a clean solution to the problem as stated unless you're working with a dialect of C that allows anonymous unions or structs. And even then, only if you can truly cast vector* to double[] as suggested elsewhere. While that would work on every architecture I've ever used, I doubt that the standard actually supports it. -- -Ed Falk, fa**@despams.r.us.com http://thespamdiaries.blogspot.com/ Aug 3 '08 #41

 P: n/a On 2 Aug 2008 at 20:06, Richard Heathfield wrote: Bartc said: >Apart the inconvenience and extra space and extra dereferencing, Right again. There ain't no such thing as a free lunch. Perhaps there's a better approach that will solve the OP's problem, but I haven't seen it yet. Any suggestions? To repeat it yet again: your solution is a C++ solution, not in the sense that it's written in (C++ but not C), but in the sense that it fits the approach and mindset of a C++ programmer. The natural C solution is type-punning by casting structs. You want to claim that this is not C? Networking is based completely on manipulating various socket structs etc. in this way. GTK builds a vast object-oriented framework in C in this way. Aug 3 '08 #42

 P: n/a In article , Antoninus Twink On 2 Aug 2008 at 20:06, Richard Heathfield wrote: >Bartc said: >>Apart the inconvenience and extra space and extra dereferencing, Right again. There ain't no such thing as a free lunch. Perhaps there's abetter approach that will solve the OP's problem, but I haven't seen ityet. Any suggestions? To repeat it yet again: your solution is a C++ solution, not in thesense that it's written in (C++ but not C), but in the sense that itfits the approach and mindset of a C++ programmer.The natural C solution is type-punning by casting structs. You want toclaim that this is not C? Networking is based completely on manipulatingvarious socket structs etc. in this way. GTK builds a vastobject-oriented framework in C in this way. And yet, in the twisted minds of the regs, none of those things are written in C... Aug 4 '08 #43

 P: n/a Kenny McCormack wrote: In article , Antoninus Twink On 2 Aug 2008 at 20:06, Richard Heathfield wrote: >>Bartc said:Apart the inconvenience and extra space and extra dereferencing,Right again. There ain't no such thing as a free lunch. Perhaps there's abetter approach that will solve the OP's problem, but I haven't seen ityet. Any suggestions? To repeat it yet again: your solution is a C++ solution, not in thesense that it's written in (C++ but not C), but in the sense that itfits the approach and mindset of a C++ programmer.The natural C solution is type-punning by casting structs. You want toclaim that this is not C? Networking is based completely on manipulatingvarious socket structs etc. in this way. GTK builds a vastobject-oriented framework in C in this way. And yet, in the twisted minds of the regs, none of those things are written in C... They are not written in 'regulars C' o no network o no graphics o no GUI o no directories o no parallelism o no threads o no nothing actually :-) -- jacob navia jacob at jacob point remcomp point fr logiciels/informatique http://www.cs.virginia.edu/~lcc-win32 Aug 4 '08 #44

 P: n/a jacob navia wrote: > They are not written in 'regulars C' o no network Right. It's the domain of other standards, not of a programming language standard. o no graphics Right. It's the domain of other standards (and less formal quasi- standards), not of a programming language standard. o no GUI You're repeating yourself. o no directories Right. It's the domain of other standards, not of a programming language standard. o no parallelism Right. It's the domain of other standards, which some experts consider premature: The state of the art, they say, is insufficiently advanced to warrant standardization. In any event, it's not an appropriate matter for a programming language standard. (And before somebody hollers "Java," read the serious and sometimes virulent criticisms that have been leveled at its attempts to parallelize.) o no threads You're repeating yourself. o no nothing actually :-) You're repeating yourself from many earlier threads. You've told us more than once that C is a dead language, that C's lack of features (both those mentioned above and others you've promoted) have rendered it obsolete, that nobody uses C any more, ... And you've been asked why, in light of this belief, you waste your own valuable time and energy stirring the ashes of this burned-out relic. But you've never explained your passion for the long-dead. Will you ever do so, I wonder? Or will you say to yourself, "Jacob, you've got better things to do than fret over rubbish" and go away? -- Er*********@sun.com Aug 4 '08 #45

 P: n/a In article , jacob navia Kenny McCormack wrote: .... >And yet, in the twisted minds of the regs, none of those things arewritten in C... They are not written in 'regulars C'o no networko no graphicso no GUIo no directorieso no parallelismo no threadso no nothing actually :-) You are absolutely right, of course. But I want to add (and this was my original point) that in the regs view, it isn't C. Period. Full stop, as some of them are want to say. To which, of course, sensible people ask: Well, if it isn't C, what is it? To which the regs say: It is "C with extensions". To which, of course, sensible people point out that toast with jelly is (and this, I know, will come as a big shock and a crushing blow to the regs) still toast. Aug 4 '08 #46

 P: n/a Eric Sosman wrote: jacob navia wrote: >>They are not written in 'regulars C'o no network Right. It's the domain of other standards, not of a programming language standard. >o no graphics Right. It's the domain of other standards (and less formal quasi- standards), not of a programming language standard. >o no GUI You're repeating yourself. >o no directories Right. It's the domain of other standards, not of a programming language standard. >o no parallelism Right. It's the domain of other standards, which some experts consider premature: The state of the art, they say, is insufficiently advanced to warrant standardization. In any event, it's not an appropriate matter for a programming language standard. (And before somebody hollers "Java," read the serious and sometimes virulent criticisms that have been leveled at its attempts to parallelize.) >o no threads You're repeating yourself. >o no nothing actually :-) You're repeating yourself from many earlier threads. You've told us more than once that C is a dead language, You are lying, as always that C's lack of features (both those mentioned above and others you've promoted) have rendered it obsolete, same lie that nobody uses C any more, ... same lie What I DID say is that people like you are killing the language making any development impossible. Your fight against standard C, your pushing of obsolete standards, your denial of anything that goes beyond int main (void) your refusal to discuss any improvements to the language is a sure way of killing C. Lucky for the rest of us, the regulars of clc are not the ones that count anywhere. -- jacob navia jacob at jacob point remcomp point fr logiciels/informatique http://www.cs.virginia.edu/~lcc-win32 Aug 4 '08 #47

 P: n/a jacob navia wrote: Kenny McCormack wrote: >In article ,Antoninus Twink >On 2 Aug 2008 at 20:06, Richard Heathfield wrote:Bartc said:Apart the inconvenience and extra space and extra dereferencing,Right again. There ain't no such thing as a free lunch. Perhapsthere's a better approach that will solve the OP's problem, but Ihaven't seen it yet. Any suggestions?To repeat it yet again: your solution is a C++ solution, not in thesense that it's written in (C++ but not C), but in the sense that itfits the approach and mindset of a C++ programmer.The natural C solution is type-punning by casting structs. You wantto claim that this is not C? Networking is based completely onmanipulating various socket structs etc. in this way. GTK builds avast object-oriented framework in C in this way. And yet, in the twisted minds of the regs, none of those things arewritten in C... They are not written in 'regulars C' ISO C. o no network Berkeley sockets. o no graphics OpenGL/X o no GUI GTK+/IBM CUA o no directories POSIX o no parallelism OpenMP o no threads pthreads o no nothing actually :-) So what are doing here so often? Aug 4 '08 #48

 P: n/a jacob navia wrote: Eric Sosman wrote: What I DID say is that people like you are killing the language making any development impossible. Remarkable that you can determine the intentions of people over a newsgroup, from seeing a few posts. Your fight against standard C, Er, that's you. your pushing of obsolete standards, No one has done this. your denial of anything that goes beyond int main (void) Nonsense. Just examine a month's worth of threads here and you'll find that all aspects of Standard C (and a little beyond too) are discussed. your refusal to discuss any improvements to the language You mean that you are sore that *your* proposals have not met with much approval here and in c.s.c? Nevertheless they have been discussed a lot. I can find huge threads on operator overloading, containers, threads etc. You're just sore that you did not emerge with the majority consensus. is a sure way of killing C. Lucky for the rest of us, the regulars of clc are not the ones that count anywhere. One would think otherwise from all the hysterical reactions these "regulars" seem to provoke from you and the trolls. Aug 4 '08 #49