I want to pass a pointer to a structure to a function, and I want to make sure not to modify one or some of the members of the structure, on a per-member basis. Can I use a language construct, like const, to specify that?
I want to pass a pointer to a structure to a function, and I want to make sure not to modify one or some of the members of the structure, on a per-member basis. Can I use a language construct, like const, to specify that?
One non-pretty solution I can think of is:
Disclaimer: the code is not meant to compile.Code:struct foo { int x, y; }; struct const_foo { const int x; int y; }; void myfunc(const_foo* p) {} int main() { foo my_foo = { 10, 10 }; myfunc((const_foo*)&my_foo); }
Is this like something you want to do?
No, in C, const is per parameter to a function or per actual variable, so you either make the entire struct const (in which case you can't modify it) or don't (in which case you CAN modify it).
In C++, you could pass a constr struct to a function, and use mutable to allow certain member to still be modifiable - however, this should be used with utter care - if you have more than a couple fo mutable members, you are probably doing something wrong.
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
Yes, something like that, but my concern with that is that I don't think that const and non-const types are compatible with each other (see 6.7.3.9), meaning using a struct through a pointer to a struct where one member is const qualified would not be guaranteed to work.
Actually, my comment wasn't to your post, but to the original post.
Your code compiles - but it's absolutely not the right thing to do, since it relies on the programmer to get the right variant of the struct at any given time.
However, if there are elements in the struct that are initialized by an initializer list (like my_foo in the example above), that have values that never change, then those can be made const in the struct. If most or all values are changed (or initialized by assigning a value to the struct itself), but only some are changed in some functions, then the const inside the struct doesn't work.
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
I suppose you can pass pointers to the individual members of the struct and make the pointers pointers-to-const as appropriate.
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
Oh!
No, it doesn't compile in C I left out the typedef and struct keyword on purpose to mock CYour code compiles - but it's absolutely not the right thing to do, since it relies on the programmer to get the right variant of the struct at any given time.
I agree it's a very hackish and bad approach, which I did mention, but I see no alternative...
Does that not just defeat the whole purpose of a struct, though?
Perhaps you could pass the certain members inside the struct that must not be changed as pointers to const or vice versa if your struct contains mostly const.
Mats:
Even mutable would not work, since I want to make sure I don't modify the member in the function, and mutable is defined in the class. Conceivably, there would be another function that has const applied to a different set of members.
laserlight:
Yes, I could do that, but unfortunately, it throws the entire concept of data aggregation and encapsulation out the window.
Then I think Elysia's solutin of passing only certain members to the function is the only workable one.
Another option is of course to build a "per-funciton test-framework", where you pass a range of data to each function, and check that the function hasn't modified something it shouldn't modify. Just make sure that you cover all branches in the function (code-coverage tools will help here).
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
Yes, but you have already thrown aggregation and encapsulation (and abstraction) out of the window by considering the internals and trying to separate how they can be modified.Originally Posted by robwhit
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
You could create a wrapper class which proxies for the underlying object and only allows access to some of the members.
Of course this gets tedious if the class is large, or if it changes often.Code:class A { public: int member_to_be_modified; int member_to_be_protected; }; class AProxy { public: AProxy(A &object) : member_to_be_modified(object.member_to_be_modified), member_to_be_protected(object.member_to_be_protected) { } int &member_to_be_modified; const int &member_to_be_protected; };
EDIT: Er, wait. This is C. Nevermind.
Last edited by brewbuck; 12-11-2008 at 02:19 PM.
Code://try //{ if (a) do { f( b); } while(1); else do { f(!b); } while(1); //}
Touche. But there is also the part about having an abstract interface, if not an implementation.Funny you say that... I was wondering about this to help specify to the test tools what variables should or should not be changed in a function. I don't have a particular test tool in mind, though.
Is this sort of specification capability par for the course with test tools?
Last edited by robwhit; 12-11-2008 at 11:28 PM. Reason: sp
I have a GotW just for your example Elysia:
http://www.gotw.ca/gotw/076.htm
According to that example, your code falls under "Criminal #3: The Cheat". Basically assuming that the same holds true for C as well as C++, it's undefined behaviour.
My homepage
Advice: Take only as directed - If symptoms persist, please see your debugger
Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"
You could always write your own small(ish) test for this purpose. Something that is based on a datastructure like this, perhaps [I just made this up based on other stuff that does roughly this sort of thing):
The actual testing code would set up a structure that contains valid (or invalid) values for the "tobetested" struct. Then make a "original" copy of the struct, call the testfunction and compare the resulting struct. Using memcmp() to compare the size number of bytes at offset, and then check if "unchanged" is true when memcmp is non-zero - that's a fail.Code:struct tobetested { int x; char s[20]; double d; }; #define VALUE(basestruct, member, type, unchanged) { #member, offsetof(basestruct, member), sizeof(type), unchanged } struct Changes { char *name; size_t offset; size_t size; bool unchanged; } struct Testcase { int caseNumber; char *caseName; int (*func)(struct tobetested *tbt); struct Changes *changes; }; struct Changes xOnlyChanges[] = { VALUE(tobetested, x, int, false), VALUE(tobetested, str, char[20], true), VALUE(tobetested, d, double, true), { NULL } }; struct Changes noChanges[] = { VALUE(tobetested, x, int, true), VALUE(tobetested, str, char[20], true), VALUE(tobetested, d, double, true), { NULL } }; #define TC(tcfunc, tcno, changes) { tcno, #tcfunc, tcfunc, changes } struct TestCase testcases[] = { TC(testCase1, 1, xOnlyChanges), TC(testCase2, 2, noChanges) };
I'm sure there are more clever ways to do this, and if you are ALWAYS using gcc, you can use "typeof(member)" instead of passing the type in as a parameter to the VALUE macro.
I once wrote a set of macros to define the contents structure as a table, and it would include the same file twice to build the data structures.
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.