I am loading an INI file and have a simple function to load values from
it. The function is overloaded with the different return types int,
double or string. A structure is defined:
typedef struct INI_KEY {
char strCategory[32];
char strKey[32];
union {
int iDefaultValue;
double dDefaultValue;
char strDefaultValue[32];
} def;
} INI_KEY;
In the implementation is a global array of INI_KEY's that list off
various categories, keys and their default value (the value to return if
it isn't in the INI):
const INI_KEY g_keys[] = {
{ "category", "keyInt", 0 },
{ "category", "keyDouble", 0.0 },
{ "category", "keyString", "foo" },
// ...
};
The problem I'm having is in the default value of the global array. The
compiler is trying to convert the double and string values to integers
and generating compiler errors. I'm sure there is a syntax to tell the
compiler what member of the union to use, I just don't know it.
--
Best regards,
Jeff jma[at]mfire.com
http://www.jm-basic.com
Try the following:
const INI_KEY g_keys[] = {
{ "category", "keyInt", .def.iDefaultValue = 0 },
{ "category", "keyDouble", .def.dDefaultValue = 0.0 },
{ "category", "keyString", .def.strDefaultValue = "foo" },
// ...
};
>
> --
> Best regards,
> Jeff jma[at]mfire.com
> http://www.jm-basic.com
> _______________________________________________
> comp.lang.forth mailing list
> comp.la...@ada-france.org
> http://www.ada-france.org/mailman/listinfo/comp.lang.forth
>
> Try the following:
>
> const INI_KEY g_keys[] = {
> { "category", "keyInt", .def.iDefaultValue = 0 },
> { "category", "keyDouble", .def.dDefaultValue = 0.0 },
> { "category", "keyString", .def.strDefaultValue = "foo" },
> // ...
> };
>
>
No go. Thanks, though.
>Jeff Massung <j...@NOSPAM.mfire.com> writes:
that only works in g++... AFAIK there is no standard way to do what
you want to do... check your compiler's docs, though.
Lukas Reck
[...]
> The problem I'm having is in the default value of the global array. The
> compiler is trying to convert the double and string values to integers
> and generating compiler errors. I'm sure there is a syntax to tell the
> compiler what member of the union to use, I just don't know it.
In general, there is no way to initialize any member other than the
first in C++ (or C) unions.
Ed
> jace...@users.sourceforge.net (Jorge Ramon Acereda Maciá) wrote
> >Try the following:
> >
> >const INI_KEY g_keys[] = {
> > { "category", "keyInt", .def.iDefaultValue = 0 },
> > { "category", "keyDouble", .def.dDefaultValue = 0.0 },
> > { "category", "keyString", .def.strDefaultValue = "foo" },
> > // ...
> >};
>
> that only works in g++... AFAIK there is no standard way to do what
> you want to do... check your compiler's docs, though.
My understanding of the gcc info pages is that it is a ISO C99
feature, so it should work on other compilers supporting the standard.
That may be... but no c++ compiler is required to support the ISO C99
standard. so most of them don't.
There are a great many very resourcefull and clever people at:
comp.lang.c++
comp.lang.c++.moderated
This is more c than c++ but if you must do it like that, all you need to do
is give yourself something to work with, just as you would in Forth:
struct INI_KEY
{
char strCategory[32];
char strKey[32];
union {
int iDefaultValue;
double dDefaultValue;
char strDefaultValue[32];
} def;
void init(char const* _category, char const* _key)
{
std::strncpy(strCategory, _category, sizeof(strCategory) - 1);
strCategory[sizeof(strCategory) - 1] = 0;
std::strncpy(strKey, _key, sizeof(strKey) - 1);
strKey[sizeof(strKey) - 1] = 0;
}
void copy(INI_KEY const& rhs)
{
std::memcpy(strCategory, rhs.strCategory, sizeof(strCategory));
std::memcpy(strKey, rhs.strKey, sizeof(strKey));
std::memcpy(&def, &rhs.def, sizeof(def));
}
INI_KEY(INI_KEY const& rhs)
{
copy(rhs);
}
INI_KEY& operator =(INI_KEY const& rhs)
{
if (this != &rhs)
copy(rhs);
return *this;
}
INI_KEY(char const*_category, char const* _key, int _i)
{
init(_category, _key);
def.iDefaultValue = _i;
}
INI_KEY(char const*_category, char const* _key, double _d)
{
init(_category, _key);
def.dDefaultValue = _d;
}
INI_KEY(char const*_category, char const* _key, char const* _s)
{
init(_category, _key);
std::strncpy(def.strDefaultValue, _s,
sizeof(def.strDefaultValue) - 1);
def.strDefaultValue[sizeof(def.strDefaultValue) - 1] = 0;
}
};
const INI_KEY g_keys[] =
{
INI_KEY("category", "keyInt", 0),
INI_KEY("category", "keyDouble", 0.0),
INI_KEY("category", "keyString", "foo")
};
int _tmain(int argc, _TCHAR* argv[])
{
INI_KEY const& ini0 = g_keys[0];
INI_KEY const& ini1 = g_keys[1];
INI_KEY const& ini2 = g_keys[2];
return 0;
}
Regards,
Conrad Weyns
> [constructor code snipped]
Thanks! Forgot about constructors in structs. Problem solved.
I have no access to a C++ Standard. But because you are using POD
(Plain Old Data) here, the ANSI C Standard will do.
6.5.7.
" A brace enclosed initialiser for a union object initialises the member
that appears first in the declaration of the union list."
The compiler does exactly what the standard prescribes.
The next question is of course, how do I do what I intend.
Therefore I have set the follow up to comp.lang.c++
where you should have posted your message in the first place.
>--
>Best regards,
> Jeff jma[at]mfire.com
> http://www.jm-basic.com
Groetjes Albert.
--
Albert van der Horst,Oranjestr 8,3511 RA UTRECHT,THE NETHERLANDS
One man-hour to invent,
One man-week to implement,
One lawyer-year to patent.
Won't constructors be run exclusively at runtime? It seems to me that
the issue of statically defined and initialized (e.g. ROM-able) unions
are still not portably implementable.
Ed
Yes, but portability isn't an issue for me. It's running on WinXP and
only WinXP.
Not to be argumentative, but aside from libraries, I've never understood
the goal of portability. Every application I've ever written would never
have been portable from the very beginning, because it used Win API or OS
X GUI functions or IrDA on the Palm, etc...
--
Best regards,
Jeff Massung jma[at]mfire.com
http://www.jm-basic.com/
> Not to be argumentative, but aside from libraries, I've never understood
> the goal of portability. Every application I've ever written would never
> have been portable from the very beginning, because it used Win API or OS
> X GUI functions or IrDA on the Palm, etc...
It depends on the kind of software you write, who uses it, and why. In
my case, software I write tends to be back-end non-GUI stuff for
industrial applications, so it might very well run on a PC one week and
an embedded system or Palm next week. Typical among such applications
are communications/control and heavy number crunching software.
Although both can (and often do) benefit from some kind of GUI, the UI
is often not an essential aspect of the software. The kind of software
I most enjoy writing has no GUI at all.
Ed
> It depends on the kind of software you write, who uses it, and why.
> [ ... ]
> The kind of software I most enjoy writing has no GUI at all.
Ditto. I just don't have that option for my job *sigh*
In your three examples, you're writing code that targets an OS. And since
the OS binds you to a particular narrow set of hardware, portability
probably isn't a big issue for you.
But portability can matter greatly in other contexts. Most of the designs
I've worked on over the past few years have been for high-volume consumer
electronics where being able to shave bucks off a design is important.
There is rarely an operating system, and you talk directly to the hardware
(usually through some abstraction). Here, portability matters because it
means we are free to choose parts based on availability and the best price
we can get.
An example of this was a design I worked on that used a Z80. It became
harder to get Z80's at a competitive price, so knowing that our software was
portable, we switched the hardware to a 8051-based design. Recompile the
code, make some low-level changes, and presto It worked. The price of the
unit went down a bit, which meant we could sell it for less than our
competitors, which meant we sold more.
One thing that many people don't have to deal with are suppliers. Tell a
supplier that your project has a dependency on a particular micro, and watch
them rub their hands together in glee. There is no need to be competitive
when you lock yourself into a particular hardware platform. But tell a
supplier that your code is portable and you could switch at any time to
another micro, and they have to be competitive.
Portability also matters when you use an OS that has already been ported to
multiple hardware platforms. A current project I'm working on is based on
uClinux, a port of Linux for MMU-less designs. With very little effort, we
can retarget our code for a wide range of hardware platforms, giving us more
options, and more opportunities for code reuse. A future design based on
this uClinux-based product will use a completely different microcontroller
that is twice as fast. No more than 5% of the code in the system will have
to change to accomplish this move.
Some people don't care about portability because they have dependencies
(such as an OS or specialized hardware). That's fine, but at least in the
world I work in, portability is a competitive advantage.
Even the most trivial static array will have run-time initialization costs
in c/c++. It may not look like it from a syntax point of view.
A.f.a.i.k, Forth per se, doesn't produce rom-able code without a special set
of words, or does it?
Conrad Weyns
<expose of circumstance skipped>
May I add:
sometimes a set of programs represent knowledge collected over
years.
Image a design shop with a pile of FORTRAN simulation programs
one meter high, written over ten years on an IBM xxxx.
They don't want to rewrite, just because that particular main frame
is no longer available.
"Jeff Massung" <j...@NOSPAM.mfire.com> wrote in message
news:vue77i...@corp.supernews.com...
> A structure is defined:
>
> typedef struct INI_KEY {
> char strCategory[32];
> char strKey[32];
>
> union {
> int iDefaultValue;
> double dDefaultValue;
> char strDefaultValue[32];
> } def;
> } INI_KEY;
>
... snip ....
> const INI_KEY g_keys[] = {
> { "category", "keyInt", 0 },
> { "category", "keyDouble", 0.0 },
> { "category", "keyString", "foo" },
> // ...
> };
>
> The problem I'm having is in the default value of the global array.
> The compiler is trying to convert the double and string values to
> integers and generating compiler errors. I'm sure there is a syntax
> to tell the compiler what member of the union to use, I just don't
> know it.
I ran into this exact same problem a few months ago. After a bit of
search what I found was the rule for unions is you can only initialise
the first element of the union.
From memory the reason given was that otherwise it would be impossible
for the compiler to pick the correct conversion. For example in the
your case above:
{ "category", "keyInt", 0 },
the 0 could be an int or a string. Which one does the compiler pick?
Jussi Jumppanen
Author of: Zeus for Windows (All new version 3.92 out now)
"The C/C++, Cobol, Java, HTML, Python, PHP, Perl programmer's editor"
Home Page: http://www.zeusedit.com