Discussion:
void* passed as funtion parameters?
(too old to reply)
Robby
2009-08-29 17:12:01 UTC
Permalink
Hello,

I figured reading up on the advanced uses of void pointer (void*) would shed
some light on what I am trying to do, but this is not working out. I read
stuff like:

http://pointersinc.blogspot.com/

but I don't see how function pointers could solve my problem.

It so happens that I have many functions that do exactly the same thing but
for different object types. I really would like to replace all these
functions by one function and alter the type of the pointer to the correct
object at function calling time (when my code actually calls the function).
For example here is what I have now:

=====================================

typedef struct tag_pc {
long LK__F1;
} pc;

typedef struct tag_ab {
long LK__F1;
} ab;

typedef struct tag_cd {
long LK__F1;
} cd;

void f1(pc *obj_pc)
{
obj_pc->LK__F1 = 10;
}

void f2(ab *obj_ab)
{
obj_ab->LK__F1 = 10;
}

void f3(cd *obj_cd)
{
obj_cd->LK__F1 = 10;
}

int main()
{
pc *obj_pc;
ab *obj_ab;
cd *obj_cd;

obj_pc = malloc (sizeof (struct tag_pc));
obj_ab = malloc (sizeof (struct tag_ab));
obj_cd = malloc (sizeof (struct tag_cd));

f1(obj_pc);
f2(obj_ab);
f3(obj_cd);

free(obj_pc);
free(obj_ab);
free(obj_cd);
return 0;
}
============================

Keeping f1(), f2() and f3 around while they carry out the exact same logic
functionality is absurb. Here is what I am trying to do:

============================

typedef struct tag_pc {
long LK__F1;
} pc;

typedef struct tag_ab {
long LK__F1;
} ab;

typedef struct tag_cd {
long LK__F1;
} cd;

void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break;
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}


int main()
{
void *x;

x = malloc (sizeof (struct tag_pc));
f1(x, 1);

x = malloc (sizeof (struct tag_ab));
f1(x, 2);

x = malloc (sizeof (struct tag_cd));
f1(x, 3);

free(x);
return 0;
}
===========================

I get a multitude of errors at the function:

void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break; <<<< error here!!!!
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}


I would have to do this for it to compile without errors:

void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
}

*but then* How do I know what pointer *type* is comming in the function ???

Any ideas that would help condense my repetitive functions into one would
really make my code tighter and easier for me to follow in the future.

All help appreciated and thankyou in advance!

Finest regards
Roberto
Alex Blekhman
2009-08-29 18:46:00 UTC
Permalink
Post by Robby
void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break; <<<< error here!!!!
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}
Yes, you get errors because there is no cast from void* to the
actual type. You should cast void* pointers before you can use
them:

pc *p = (pc *)x;
p->LK__F1 = 10;
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
}
*but then* How do I know what pointer *type* is comming in the
function ???
This is one of the weakness of the C language. There is no way to
know what type it is. In the C++ language this problem can be
solved with trivial template function:

template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}

In C the best you can do is to make a macro:

#define SET_F1(p, val) (p)->LK__F1 = (val)

then you can use it like this:

SET_F1(obj_pc, 10);
SET_F1(obj_ab, 10);
SET_F1(obj_cd, 10);


HTH
Alex
Post by Robby
Any ideas that would help condense my repetitive functions into one would
really make my code tighter and easier for me to follow in the
future.
All help appreciated and thankyou in advance!
Finest regards
Roberto
Robby
2009-08-29 19:23:01 UTC
Permalink
Hello Alex,
Post by Alex Blekhman
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}
wow! that's exactly what I need! But unfortunately PIC MCU'S don't support
C++, they only support assembler or C. Some revolutionary MCU's such as ARM
which are a little more powerfull are starting to accept C++. But not PICs
... mayby someday they will.

Getting back to what you have proposed as the only solution:

#define SET_F1(p, val) (p)->LK__F1 = (val)

But I really can't use this because my real functions are not just composed
of :

obj_pc->LK__F1 = 10;

there is a lot of logic such as for loops and if statements which have many
encompass lines of code using the "obj_pc" pointer. :-(

So now what, is this a wall that I am hitting ? Am I stuck having to keep
repetitive code?

Thanks for your reply, get back , standing by!
--
Best regards
Roberto
Post by Alex Blekhman
Post by Robby
void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break; <<<< error here!!!!
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}
Yes, you get errors because there is no cast from void* to the
actual type. You should cast void* pointers before you can use
pc *p = (pc *)x;
p->LK__F1 = 10;
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
}
*but then* How do I know what pointer *type* is comming in the function ???
This is one of the weakness of the C language. There is no way to
know what type it is. In the C++ language this problem can be
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}
#define SET_F1(p, val) (p)->LK__F1 = (val)
SET_F1(obj_pc, 10);
SET_F1(obj_ab, 10);
SET_F1(obj_cd, 10);
HTH
Alex
Post by Robby
Any ideas that would help condense my repetitive functions into one would
really make my code tighter and easier for me to follow in the future.
All help appreciated and thankyou in advance!
Finest regards
Roberto
Alex Blekhman
2009-08-29 19:46:03 UTC
Permalink
Post by Robby
#define SET_F1(p, val) (p)->LK__F1 = (val)
But I really can't use this because my real functions are not
obj_pc->LK__F1 = 10;
there is a lot of logic such as for loops and if statements
which have many encompass lines of code using the "obj_pc"
pointer. :-(
Yes, this is one of the annoyances of C. That's why huge multiline
macros are not uncommon in the mature C projects. Another
alternative is to factor out the common part into a separate
struct:

typedef struct tag_common
{
long LK__F1;
// ...
} common;

typedef struct tag_ab
{
common cmn;

// ...
// other members
} ab;

Then, when you need to perform a common action that involves
LK__F1 you call a function that accepts common*:

void f1(common* pcmn, long val)
{
pcmn->LK__F1 = val;

// ...
// other code that uses `common'
}

f1(&obj_pc->cmn, 10);
f1(&obj_ab->cmn, 20);
f1(&obj_cd->cmn, 30);


HTH
Alex
Robby
2009-08-29 20:24:01 UTC
Permalink
Hello Alex,

hmmm, that's interesting. Adopting the grouping of common and uncommon
members is pretty much a dramatic modification to my code though and I don't
know how it will impact the time of integrating this new methodology given
that everything else works perfectly. I will have to think about this one,
but it is a valid alternative.

I am still cleaning code. Once I finish organizing my code things will be a
little clearer and might give it a try.

Thanks Alex, your help was very appreciated.
--
Best regards
Roberto
Post by Alex Blekhman
Post by Robby
#define SET_F1(p, val) (p)->LK__F1 = (val)
But I really can't use this because my real functions are not
obj_pc->LK__F1 = 10;
there is a lot of logic such as for loops and if statements
which have many encompass lines of code using the "obj_pc"
pointer. :-(
Yes, this is one of the annoyances of C. That's why huge multiline
macros are not uncommon in the mature C projects. Another
alternative is to factor out the common part into a separate
typedef struct tag_common
{
long LK__F1;
// ...
} common;
typedef struct tag_ab
{
common cmn;
// ...
// other members
} ab;
Then, when you need to perform a common action that involves
void f1(common* pcmn, long val)
{
pcmn->LK__F1 = val;
// ...
// other code that uses `common'
}
f1(&obj_pc->cmn, 10);
f1(&obj_ab->cmn, 20);
f1(&obj_cd->cmn, 30);
HTH
Alex
Ben Voigt [C++ MVP]
2009-08-30 02:29:02 UTC
Permalink
Post by Robby
Hello Alex,
Post by Alex Blekhman
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}
wow! that's exactly what I need! But unfortunately PIC MCU'S don't support
C++, they only support assembler or C. Some revolutionary MCU's such as ARM
which are a little more powerfull are starting to accept C++. But not PICs
... mayby someday they will.
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C. And don’t trust
the alternative called "embedded C++". While a subset of C++ that excludes
exceptions makes sense for microcontrollers, the folks behind embedded C++
didn't have a good understanding of runtime cost of various features.

For example, AVR chips are just as simple as PICs but have g++ (a good C++
compiler) capable of producing AVR code.


__________ Information from ESET NOD32 Antivirus, version of virus signature database 4380 (20090829) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com
Robby
2009-08-30 11:33:01 UTC
Permalink
Hello Ben,
Post by Ben Voigt [C++ MVP]
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C.
Yes, your right, and its just that not all compiler manufacturers offer C++
for MCUs either. 6 years ago when I was looking for C++ compilers for MCUs,
there was not to many around but, yes they were existant. One of the good
ones I remember was Code warior but very expensive...

But, on another note Ben, why do some people put a cross on C++ when it
comes to microcontrollers. You can see here that C++ is really not that
welcome:

http://stackoverflow.com/questions/452139/writing-firmware-assembly-or-high-level

I don't know how old the article is, the posts only say the day/month. There
seems to be the amount of months that the artical was posted from up on the
top right of the page.

I am now searching for a new compiler that does both C/C++ for Microchip
Pics.
I am looking around but, this time I want to pick one that is solid with
minimal bugs. Any suggestions? My current compiler is horrible, and I don't
want to make that mistake again.

So, if the compiler can do C/C++, and one day I want to switch to C++, I
would be able to replace my structures to classes and also use all that good
stuff that comes witn C++ such as templates and stl and so forth.
Post by Ben Voigt [C++ MVP]
And don’t trust the alternative called "embedded C++". While a subset of C++ that >excludes exceptions makes sense for microcontrollers, the folks behind embedded >C++ didn't have a good understanding of runtime cost of various features.
Okay!

Thanks for your feedback!
--
Best regards
Roberto
Post by Ben Voigt [C++ MVP]
Post by Robby
Hello Alex,
Post by Alex Blekhman
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}
wow! that's exactly what I need! But unfortunately PIC MCU'S don't support
C++, they only support assembler or C. Some revolutionary MCU's such as ARM
which are a little more powerfull are starting to accept C++. But not PICs
... mayby someday they will.
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C. And don’t trust
the alternative called "embedded C++". While a subset of C++ that excludes
exceptions makes sense for microcontrollers, the folks behind embedded C++
didn't have a good understanding of runtime cost of various features.
For example, AVR chips are just as simple as PICs but have g++ (a good C++
compiler) capable of producing AVR code.
__________ Information from ESET NOD32 Antivirus, version of virus signature database 4380 (20090829) __________
The message was checked by ESET NOD32 Antivirus.
http://www.eset.com
Ben Voigt [C++ MVP]
2009-08-31 21:40:57 UTC
Permalink
Post by Robby
Hello Ben,
Post by Ben Voigt [C++ MVP]
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C.
Yes, your right, and its just that not all compiler manufacturers offer C++
for MCUs either. 6 years ago when I was looking for C++ compilers for MCUs,
there was not to many around but, yes they were existant. One of the good
ones I remember was Code warior but very expensive...
But, on another note Ben, why do some people put a cross on C++ when it
comes to microcontrollers. You can see here that C++ is really not that
http://stackoverflow.com/questions/452139/writing-firmware-assembly-or-high-level
I'd guess it's because they've seen some really bloated C++ programs, they
think that all C++ programs have to be. It just isn't true. Well written
(i.e. respect typing, use prototypes, etc) C programs are also valid as C++.
And many C++-specific features have no extra cost at runtime (the compiler
has to work a little harder, or sometimes a lot harder in the case of
templates).

As you can see, the top rated answer in that thread is very pro-C++, for
many of the same reasons I am.
Post by Robby
I don't know how old the article is, the posts only say the day/month. There
seems to be the amount of months that the artical was posted from up on the
top right of the page.
I am now searching for a new compiler that does both C/C++ for Microchip
Pics.
I am looking around but, this time I want to pick one that is solid with
minimal bugs. Any suggestions? My current compiler is horrible, and I don't
want to make that mistake again.
There are a few different families of PIC, you have to specify which one.

It looks like IAR makes a compiler which will be quite good if their other
compilers are any indication. But there's no free "kickstart" edition.
There is a 30-day trial so you can see whether it's better behaved than the
one you've got.

You also might consider one of the other microcontroller families that are
about the same cost and feature set as PICs, with better compiler support.
For example, AVR and MSP430.
Post by Robby
So, if the compiler can do C/C++, and one day I want to switch to C++, I
would be able to replace my structures to classes and also use all that good
stuff that comes witn C++ such as templates and stl and so forth.
Yes, except that STL is pretty exception-heavy, so it isn't the best fit for
embedded code. But there are other libraries out there that would be fine.
In general the same methods that worked in C will work in C++, but you can
often get a lot better type-safety and program organization.
Post by Robby
Post by Ben Voigt [C++ MVP]
And don’t trust the alternative called "embedded C++". While a subset of
C++ that >excludes exceptions makes sense for microcontrollers, the folks
behind embedded >C++ didn't have a good understanding of runtime cost of
various features.
Okay!
Thanks for your feedback!
--
Best regards
Roberto
Post by Ben Voigt [C++ MVP]
Post by Robby
Hello Alex,
Post by Alex Blekhman
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}
wow! that's exactly what I need! But unfortunately PIC MCU'S don't support
C++, they only support assembler or C. Some revolutionary MCU's such as ARM
which are a little more powerfull are starting to accept C++. But not PICs
... mayby someday they will.
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C. And don’t trust
the alternative called "embedded C++". While a subset of C++ that excludes
exceptions makes sense for microcontrollers, the folks behind embedded C++
didn't have a good understanding of runtime cost of various features.
For example, AVR chips are just as simple as PICs but have g++ (a good C++
compiler) capable of producing AVR code.
__________ Information from ESET NOD32 Antivirus, version of virus
signature database 4380 (20090829) __________
The message was checked by ESET NOD32 Antivirus.
http://www.eset.com
Robby
2009-09-01 05:15:01 UTC
Permalink
Hello Ben,
Post by Ben Voigt [C++ MVP]
As you can see, the top rated answer in that thread is very pro-C++, for
many of the same reasons I am.
Yes, it is.
Post by Ben Voigt [C++ MVP]
There are a few different families of PIC, you have to specify which one.
I am gearing up for the PIC24 series (16 bit) family. I was thinking of
going for the 32 bit PIC. I don't know, I think it would be alot easier to
port from 8 bit to 16 bit rather than porting from 8 bit to 32 bit. I do need
speed, but soon the new PIC24's will be available with 60 MIPS as opposed to
the existing 40 MIPS. Which for what I am doing is plenty. And the PIC32 is
80 MIPS, so its not that I would really gain all that much more speed.
Post by Ben Voigt [C++ MVP]
It looks like IAR makes a compiler which will be quite good
Yeah, many people have said positive things about IAR. But I don;t think IAR
supports MC.
Post by Ben Voigt [C++ MVP]
You also might consider one of the other microcontroller families that are
about the same cost and feature set as PICs, with better compiler support.
For example, AVR and MSP430.
Could be an option!
--
Best regards
Roberto
Post by Ben Voigt [C++ MVP]
Post by Robby
Hello Ben,
Post by Ben Voigt [C++ MVP]
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C.
Yes, your right, and its just that not all compiler manufacturers offer C++
for MCUs either. 6 years ago when I was looking for C++ compilers for MCUs,
there was not to many around but, yes they were existant. One of the good
ones I remember was Code warior but very expensive...
But, on another note Ben, why do some people put a cross on C++ when it
comes to microcontrollers. You can see here that C++ is really not that
http://stackoverflow.com/questions/452139/writing-firmware-assembly-or-high-level
I'd guess it's because they've seen some really bloated C++ programs, they
think that all C++ programs have to be. It just isn't true. Well written
(i.e. respect typing, use prototypes, etc) C programs are also valid as C++.
And many C++-specific features have no extra cost at runtime (the compiler
has to work a little harder, or sometimes a lot harder in the case of
templates).
As you can see, the top rated answer in that thread is very pro-C++, for
many of the same reasons I am.
Post by Robby
I don't know how old the article is, the posts only say the day/month. There
seems to be the amount of months that the artical was posted from up on the
top right of the page.
I am now searching for a new compiler that does both C/C++ for Microchip
Pics.
I am looking around but, this time I want to pick one that is solid with
minimal bugs. Any suggestions? My current compiler is horrible, and I don't
want to make that mistake again.
There are a few different families of PIC, you have to specify which one.
It looks like IAR makes a compiler which will be quite good if their other
compilers are any indication. But there's no free "kickstart" edition.
There is a 30-day trial so you can see whether it's better behaved than the
one you've got.
You also might consider one of the other microcontroller families that are
about the same cost and feature set as PICs, with better compiler support.
For example, AVR and MSP430.
Post by Robby
So, if the compiler can do C/C++, and one day I want to switch to C++, I
would be able to replace my structures to classes and also use all that good
stuff that comes witn C++ such as templates and stl and so forth.
Yes, except that STL is pretty exception-heavy, so it isn't the best fit for
embedded code. But there are other libraries out there that would be fine.
In general the same methods that worked in C will work in C++, but you can
often get a lot better type-safety and program organization.
Post by Robby
Post by Ben Voigt [C++ MVP]
And don’t trust the alternative called "embedded C++". While a subset of
C++ that >excludes exceptions makes sense for microcontrollers, the folks
behind embedded >C++ didn't have a good understanding of runtime cost of
various features.
Okay!
Thanks for your feedback!
--
Best regards
Roberto
Post by Ben Voigt [C++ MVP]
Post by Robby
Hello Alex,
Post by Alex Blekhman
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}
wow! that's exactly what I need! But unfortunately PIC MCU'S don't support
C++, they only support assembler or C. Some revolutionary MCU's such as ARM
which are a little more powerfull are starting to accept C++. But not PICs
... mayby someday they will.
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C. And don’t trust
the alternative called "embedded C++". While a subset of C++ that excludes
exceptions makes sense for microcontrollers, the folks behind embedded C++
didn't have a good understanding of runtime cost of various features.
For example, AVR chips are just as simple as PICs but have g++ (a good C++
compiler) capable of producing AVR code.
__________ Information from ESET NOD32 Antivirus, version of virus
signature database 4380 (20090829) __________
The message was checked by ESET NOD32 Antivirus.
http://www.eset.com
Ben Voigt [C++ MVP]
2009-09-02 20:46:48 UTC
Permalink
Post by Robby
Hello Ben,
Post by Ben Voigt [C++ MVP]
There are a few different families of PIC, you have to specify which one.
I am gearing up for the PIC24 series (16 bit) family. I was thinking of
going for the 32 bit PIC. I don't know, I think it would be alot easier to
port from 8 bit to 16 bit rather than porting from 8 bit to 32 bit. I do need
speed, but soon the new PIC24's will be available with 60 MIPS as opposed to
the existing 40 MIPS. Which for what I am doing is plenty. And the PIC32 is
80 MIPS, so its not that I would really gain all that much more speed.
Post by Ben Voigt [C++ MVP]
It looks like IAR makes a compiler which will be quite good
Yeah, many people have said positive things about IAR. But I don;t think IAR
supports MC.
What do you mean by "MC"? IAR supports a large number of microcontrollers,
you can see the list here: http://iar.com/website1/1.0.1.0/675/1/
Robby
2009-09-19 23:17:01 UTC
Permalink
Hello Ben,

Sorry for the delay!

"What do you mean by "MC"? IAR supports a large number of microcontrollers,
you can see the list here: http://iar.com/website1/1.0.1.0/675/1/ "

MC = Micorchip !

I always thought that they would support MC PIC 24 familly, but it seems
like they don't, see here:

http://iar.com/website1/1.0.1.0/675/1/

I am looking for an affordable PIC compiler, but I am having a hard time
finding one. IAR is aprroximately 4K$.

I am currently loking at Mikroc:

http://www.mikroe.com/en/compilers/mikroc/pic/

Although it doesn't do C++... what do you think about Mikroc?
--
Best regards
Roberto
Post by Ben Voigt [C++ MVP]
Post by Robby
Hello Ben,
Post by Ben Voigt [C++ MVP]
There are a few different families of PIC, you have to specify which one.
I am gearing up for the PIC24 series (16 bit) family. I was thinking of
going for the 32 bit PIC. I don't know, I think it would be alot easier to
port from 8 bit to 16 bit rather than porting from 8 bit to 32 bit. I do need
speed, but soon the new PIC24's will be available with 60 MIPS as opposed to
the existing 40 MIPS. Which for what I am doing is plenty. And the PIC32 is
80 MIPS, so its not that I would really gain all that much more speed.
Post by Ben Voigt [C++ MVP]
It looks like IAR makes a compiler which will be quite good
Yeah, many people have said positive things about IAR. But I don;t think IAR
supports MC.
What do you mean by "MC"? IAR supports a large number of microcontrollers,
you can see the list here: http://iar.com/website1/1.0.1.0/675/1/
Tim Roberts
2009-09-20 00:02:12 UTC
Permalink
Post by Robby
"What do you mean by "MC"? IAR supports a large number of microcontrollers,
you can see the list here: http://iar.com/website1/1.0.1.0/675/1/ "
MC = Micorchip !
I always thought that they would support MC PIC 24 familly, but it seems
http://iar.com/website1/1.0.1.0/675/1/
I am looking for an affordable PIC compiler, but I am having a hard time
finding one. IAR is aprroximately 4K$.
The Microchip MPLAB compiler is free. You have to pay if you want the
"professional" version with "advanced optimizations", but the vast majority
of PIC projects are very simple, straightforward programs with short
functions where the optimizations make no measureable difference.
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
Robby
2009-09-20 03:04:02 UTC
Permalink
Hello Tim,

Mikroc has an interesting amount of samples and development boards.

see: http://www.mikroe.com/en/tools/
(scroll down towards the end)

Although I looked at the samples at MC and they are not as clear as the ones
provided by Mikroc. And I don't think that he samples in Mikroc are fully
portable to MPLAB because Mikroc has their own libraries.

Nonetheless, I haven't decided weather I would go with MPLAB or Mikroc yet.
The 249$ start kit for Mikroc is not a problem. See:

http://www.mikroe.com/en/compilers/mikroc/pro/pic/

Do you prfer MPLAB?

The reason I was complaining about cost is that I wanted a compiler for
MCU's that could do C and C++. I really still have that template limitation
that is bothering me and eventually it would of been nice to have them
available in the compiler.

I was looking at Uli's proposition, I still haven't tried it, I thinnk I
will have problems because I don't quite understand it fully. But I will do
some tests the best I can. :-)

I wonder why Microsoft doesn't compile code for MCU's. Maybe the time has
come since the embedded MCU market is getting huge. It would be nice to
program our code in VC++ and by selecting the MCU of your choice, VC++ would
generate the appropriate hex file. I don't know if it would be possible
though! .... There's a business idea!
--
Best regards
Roberto
Post by Tim Roberts
Post by Robby
"What do you mean by "MC"? IAR supports a large number of microcontrollers,
you can see the list here: http://iar.com/website1/1.0.1.0/675/1/ "
MC = Micorchip !
I always thought that they would support MC PIC 24 familly, but it seems
http://iar.com/website1/1.0.1.0/675/1/
I am looking for an affordable PIC compiler, but I am having a hard time
finding one. IAR is aprroximately 4K$.
The Microchip MPLAB compiler is free. You have to pay if you want the
"professional" version with "advanced optimizations", but the vast majority
of PIC projects are very simple, straightforward programs with short
functions where the optimizations make no measureable difference.
--
Providenza & Boekelheide, Inc.
Tim Roberts
2009-09-22 03:34:27 UTC
Permalink
Post by Robby
Nonetheless, I haven't decided weather I would go with MPLAB or Mikroc yet.
http://www.mikroe.com/en/compilers/mikroc/pro/pic/
Do you prfer MPLAB?
I use it because it was free. I didn't go looking for other tools. Most
microprocessor projects are small and well-contained, and not particular
suitable to complicated designs. Remember, many of these microprocessors
have memories measuring in the hundreds of bytes, which does not leave room
for much compiler-generated template junk.
Post by Robby
I wonder why Microsoft doesn't compile code for MCU's. Maybe the time has
come since the embedded MCU market is getting huge.
Not in comparison. The market for embedded MCU compilers is insignificant
compared to that for Visual C++.
Post by Robby
It would be nice to
program our code in VC++ and by selecting the MCU of your choice, VC++ would
generate the appropriate hex file. I don't know if it would be possible
though! .... There's a business idea!
Visual Studio already supports code generation for devices that support
Windows CE or Windows Mobile. However, those processors are miles above
the kinds of processors we're talking about.
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
Robby
2009-09-23 21:48:01 UTC
Permalink
Hello Tim,

Well I have finally decided, I am going for MPLAB.

Its impressive that you can program MCU's aswell as VC++ for PC
applications. :-)

See ya Tim!
--
Best regards
Roberto
Post by Tim Roberts
Post by Robby
Nonetheless, I haven't decided weather I would go with MPLAB or Mikroc yet.
http://www.mikroe.com/en/compilers/mikroc/pro/pic/
Do you prfer MPLAB?
I use it because it was free. I didn't go looking for other tools. Most
microprocessor projects are small and well-contained, and not particular
suitable to complicated designs. Remember, many of these microprocessors
have memories measuring in the hundreds of bytes, which does not leave room
for much compiler-generated template junk.
Post by Robby
I wonder why Microsoft doesn't compile code for MCU's. Maybe the time has
come since the embedded MCU market is getting huge.
Not in comparison. The market for embedded MCU compilers is insignificant
compared to that for Visual C++.
Post by Robby
It would be nice to
program our code in VC++ and by selecting the MCU of your choice, VC++ would
generate the appropriate hex file. I don't know if it would be possible
though! .... There's a business idea!
Visual Studio already supports code generation for devices that support
Windows CE or Windows Mobile. However, those processors are miles above
the kinds of processors we're talking about.
--
Providenza & Boekelheide, Inc.
Ben Voigt [C++ MVP]
2009-09-29 22:57:21 UTC
Permalink
Post by Tim Roberts
Post by Robby
Nonetheless, I haven't decided weather I would go with MPLAB or Mikroc yet.
http://www.mikroe.com/en/compilers/mikroc/pro/pic/
Do you prfer MPLAB?
I use it because it was free. I didn't go looking for other tools. Most
microprocessor projects are small and well-contained, and not particular
suitable to complicated designs. Remember, many of these microprocessors
have memories measuring in the hundreds of bytes, which does not leave room
for much compiler-generated template junk.
Templates, when used carefully, don't take up extra space. Think of the
typical MAX routine, implemented as either a macro or template function.
The template will generate just as good code (after being inlined), while
being type-safe and immune to argument side-effects being executed
repeatedly.
Post by Tim Roberts
Post by Robby
I wonder why Microsoft doesn't compile code for MCU's. Maybe the time has
come since the embedded MCU market is getting huge.
Not in comparison. The market for embedded MCU compilers is insignificant
compared to that for Visual C++.
Post by Robby
It would be nice to
program our code in VC++ and by selecting the MCU of your choice, VC++ would
generate the appropriate hex file. I don't know if it would be possible
though! .... There's a business idea!
Visual Studio already supports code generation for devices that support
Windows CE or Windows Mobile. However, those processors are miles above
the kinds of processors we're talking about.
--
Providenza & Boekelheide, Inc.
Robby
2009-08-30 11:33:01 UTC
Permalink
Hello Ben,
Post by Ben Voigt [C++ MVP]
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C.
Yes, your right, and its just that not all compiler manufacturers offer C++
for MCUs either. 6 years ago when I was looking for C++ compilers for MCUs,
there was not to many around but, yes they were existant. One of the good
ones I remember was Code warior but very expensive...

But, on another note Ben, why do some people put a cross on C++ when it
comes to microcontrollers. You can see here that C++ is really not that
welcome:

http://stackoverflow.com/questions/452139/writing-firmware-assembly-or-high-level

I don't know how old the article is, the posts only say the day/month. There
seems to be the amount of months that the artical was posted from up on the
top right of the page.

I am now searching for a new compiler that does both C/C++ for Microchip
Pics.
I am looking around but, this time I want to pick one that is solid with
minimal bugs. Any suggestions? My current compiler is horrible, and I don't
want to make that mistake again.

So, if the compiler can do C/C++, and one day I want to switch to C++, I
would be able to replace my structures to classes and also use all that good
stuff that comes witn C++ such as templates and stl and so forth.
Post by Ben Voigt [C++ MVP]
And don’t trust the alternative called "embedded C++". While a subset of C++ that >excludes exceptions makes sense for microcontrollers, the folks behind embedded >C++ didn't have a good understanding of runtime cost of various features.
Okay!

Thanks for your feedback!
--
Best regards
Roberto
Post by Ben Voigt [C++ MVP]
Post by Robby
Hello Alex,
Post by Alex Blekhman
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}
wow! that's exactly what I need! But unfortunately PIC MCU'S don't support
C++, they only support assembler or C. Some revolutionary MCU's such as ARM
which are a little more powerfull are starting to accept C++. But not PICs
... mayby someday they will.
Maybe your C compiler vendor has fed you this line, but C++ support has
nothing to do with the capability of the target processor. It's purely a
compiler feature, both C and C++ compile to machine code just like assembler
does, and if you don't use the expensive C++ features like exceptions, the
C++ code is often even smaller and more efficient than C. And don’t trust
the alternative called "embedded C++". While a subset of C++ that excludes
exceptions makes sense for microcontrollers, the folks behind embedded C++
didn't have a good understanding of runtime cost of various features.
For example, AVR chips are just as simple as PICs but have g++ (a good C++
compiler) capable of producing AVR code.
__________ Information from ESET NOD32 Antivirus, version of virus signature database 4380 (20090829) __________
The message was checked by ESET NOD32 Antivirus.
http://www.eset.com
Barry Schwarz
2009-08-29 20:54:40 UTC
Permalink
On Sat, 29 Aug 2009 21:46:00 +0300, "Alex Blekhman"
Post by Alex Blekhman
Post by Robby
void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break; <<<< error here!!!!
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}
Yes, you get errors because there is no cast from void* to the
actual type. You should cast void* pointers before you can use
pc *p = (pc *)x;
p->LK__F1 = 10;
In C, as opposed to C++, object pointers can be converted to and from
pointer to void without using a cast.

It would have been nice if the OP had bothered to indicate what the
error was. As near as I can tell, the first error (of many) is
failing to follow the case label with a statement.
--
Remove del for email
Alex Blekhman
2009-08-29 21:18:05 UTC
Permalink
Post by Barry Schwarz
Post by Robby
void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break; <<<< error here!!!!
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}
[...]
In C, as opposed to C++, object pointers can be converted to and
from pointer to void without using a cast.
It would have been nice if the OP had bothered to indicate what
the error was. As near as I can tell, the first error (of many)
is failing to follow the case label with a statement.
Good catch. I have missed this silly error completely.

Alex
Robby
2009-08-29 21:59:01 UTC
Permalink
Hello Barry,

==========================================
typedef struct tag_pc {
long LK__F1;
} pc; <<< 2nd error points here

typedef struct tag_ab {
long LK__F1;
} ab; <<< 5th error points here

typedef struct tag_cd {
long LK__F1;
} cd;

void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break; <<< 1st & 3rd error points here
case 2: ab *p = x; break; <<< 4th error points here
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}


int main()
{
void *x;

x = malloc (sizeof (struct tag_pc));
f1(x, 1);

x = malloc (sizeof (struct tag_ab));
f1(x, 2);

x = malloc (sizeof (struct tag_cd));
f1(x, 3);

free(x);
return 0;
}
===============================
Here are the 1st 5 errors:

1>c:\_dts_programming\c_programming\c\c_tests\c_string_samples\misc_c_samples\codeuniforming.c(85)
: error C2275: 'pc' : illegal use of this type as an expression

1>c:\_dts_programming\c_programming\c\c_tests\c_string_samples\misc_c_samples\codeuniforming.c(64) : see declaration of 'pc'

1>c:\_dts_programming\c_programming\c\c_tests\c_string_samples\misc_c_samples\codeuniforming.c(85) : error C2065: 'p' : undeclared identifier

1>c:\_dts_programming\c_programming\c\c_tests\c_string_samples\misc_c_samples\codeuniforming.c(86)
: error C2275: 'ab' : illegal use of this type as an expression

1>
c:\_dts_programming\c_programming\c\c_tests\c_string_samples\misc_c_samples\codeuniforming.c(68) : see declaration of 'ab'

==============================================

I was hoping for the following to work:

========================
void f1(void *x)
{
//pc *p = x;

x->LK__F1 = 10;

...
}
========================

But the above gives 1 error:

1>c:\_dts_programming\c_programming\c\c_tests\c_string_samples\misc_c_samples\codeuniforming.c(81)
: error C2223: left of '->LK__F1' must point to struct/union


I know that the following declaration

pc *p = x;

should be before any code!
--
Best regards
Roberto
Post by Barry Schwarz
On Sat, 29 Aug 2009 21:46:00 +0300, "Alex Blekhman"
Post by Alex Blekhman
Post by Robby
void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break; <<<< error here!!!!
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}
Yes, you get errors because there is no cast from void* to the
actual type. You should cast void* pointers before you can use
pc *p = (pc *)x;
p->LK__F1 = 10;
In C, as opposed to C++, object pointers can be converted to and from
pointer to void without using a cast.
It would have been nice if the OP had bothered to indicate what the
error was. As near as I can tell, the first error (of many) is
failing to follow the case label with a statement.
--
Remove del for email
Igor Tandetnik
2009-08-30 00:30:48 UTC
Permalink
Post by Robby
typedef struct tag_pc {
long LK__F1;
} pc;
typedef struct tag_ab {
long LK__F1;
} ab;
typedef struct tag_cd {
long LK__F1;
} cd;
void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break;
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}
In C, you can only declare variables at the beginning of a block. Here,
you are declaring them in the middle of a block (the one associated with
the switch statement).
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
}
*but then* How do I know what pointer *type* is comming in the
function ???
Since all the structures are layout-compatible, it doesn't really
matter. LK__F1 is the same size and at the same offset in all three
structures, so the assignment would work the same regardless of which of
the three types you cast to. Your code should work as written.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-08-30 02:28:02 UTC
Permalink
Hello Igor,
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
}
*but then* How do I know what pointer *type* is comming in the
function ???
Since all the structures are layout-compatible, it doesn't really
matter. LK__F1 is the same size and at the same offset in all three
structures, so the assignment would work the same regardless of which of
the three types you cast to. Your code should work as written.
Yes, but I wanted to get away with writting the above function without using
Post by Robby
pc *p = x;
something like this:

========================
void f1(void *x)
{
//pc *p = x;

x->LK__F1 = 10;

...
}
========================

But in C we can't. Unless I don't understand what you mean.

Why is everyone talking about a cast. Is there a cast in this line? :

//pc *p = x;

I always thought for a cast we do this:

pc *p = (pc*) x;

Thanks to all for your help!
--
Best regards
Roberto
Post by Robby
Post by Robby
typedef struct tag_pc {
long LK__F1;
} pc;
typedef struct tag_ab {
long LK__F1;
} ab;
typedef struct tag_cd {
long LK__F1;
} cd;
void f1(void *x, int type)
{
switch(type)
{
case 1: pc *p = x; break;
case 2: ab *p = x; break;
case 2: cd *p = x; break;
}
p->LK__F1 = 10;
}
In C, you can only declare variables at the beginning of a block. Here,
you are declaring them in the middle of a block (the one associated with
the switch statement).
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
}
*but then* How do I know what pointer *type* is comming in the function ???
Since all the structures are layout-compatible, it doesn't really
matter. LK__F1 is the same size and at the same offset in all three
structures, so the assignment would work the same regardless of which of
the three types you cast to. Your code should work as written.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Igor Tandetnik
2009-08-30 03:03:47 UTC
Permalink
Post by Robby
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
}
*but then* How do I know what pointer *type* is comming in the function ???
Since all the structures are layout-compatible, it doesn't really
matter. LK__F1 is the same size and at the same offset in all three
structures, so the assignment would work the same regardless of
which of the three types you cast to. Your code should work as
written.
Yes, but I wanted to get away with writting the above function
Post by Robby
pc *p = x;
Why? Are you being charged per line of code?
Post by Robby
But in C we can't. Unless I don't understand what you mean.
"Your code should work as written" sounds pretty unambiguous to me.
Post by Robby
//pc *p = x;
Well, not a cast, but there's a conversion (once you remove two slashes
in front so that it's not just a comment). In C++, such a conversion
would in fact require an explicit cast, but in C it happens implicitly.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Igor Tandetnik
2009-08-30 12:36:04 UTC
Permalink
The code in the function below really doesn't mean much but its just
to illustrate that keeping the cast(s) doesn't get rid of the
redundance in the f1() function. I showed an example below where
suppose I have more code residing in f1(), keeping the casts don't
solve the problem. I understand the part about the casts, but am I
supposed to end up with something like this for all my functions?
============================
typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
} pc;
typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
} ab;
typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
} cd;
void f1(void *x, int type, int z)
{
int y;
pc *p = x;
ab *q =x;
cd *r =x;
switch(type)
{
for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
q->LK__F1 = y;
q->LK__F2 = (y+12);
}
q->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
r->LK__F1 = y;
r->LK__F2 = (y+12);
}
r->h = y+z;
}
break;
}
}
Just make it

void f1(void *x, int z)
{
pc *p = x;

if (z >= 0 && z < 100) {
p->LK__F1 = z;
p->LK__F2 = z+12;
}
p->h = 99 + z;
}

Again - since all three structures are identical, it doesn't matter
which one you convert to.
int main()
{
void *x;
x = malloc (sizeof (struct tag_pc));
f1(x, 1);
Does that compile? Your function is declared to take three parameters.
I find f1() very redundant, and bulky, wouldn't you agree?
Not my version of it, no. Speaking of redundant - the redundancy began
when you declared three different structures with identical members, so
I don't think you have standing to complain about it now. What purpose
was that supposed to achieve, anyway?
Igor, I am looking for an alternative, and gentlemen in this post have
listed the alternatives
And you wouldn't take the alternative I've proposed because you don't
consider me a gentleman, I suppose.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-08-31 18:00:01 UTC
Permalink
Post by Igor Tandetnik
And you wouldn't take the alternative I've proposed because you don't
consider me a gentleman, I suppose.
Well, you supposed wrong!
--
Best regards
Roberto
Post by Igor Tandetnik
The code in the function below really doesn't mean much but its just
to illustrate that keeping the cast(s) doesn't get rid of the
redundance in the f1() function. I showed an example below where
suppose I have more code residing in f1(), keeping the casts don't
solve the problem. I understand the part about the casts, but am I
supposed to end up with something like this for all my functions?
============================
typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
} pc;
typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
} ab;
typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
} cd;
void f1(void *x, int type, int z)
{
int y;
pc *p = x;
ab *q =x;
cd *r =x;
switch(type)
{
for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
q->LK__F1 = y;
q->LK__F2 = (y+12);
}
q->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
r->LK__F1 = y;
r->LK__F2 = (y+12);
}
r->h = y+z;
}
break;
}
}
Just make it
void f1(void *x, int z)
{
pc *p = x;
if (z >= 0 && z < 100) {
p->LK__F1 = z;
p->LK__F2 = z+12;
}
p->h = 99 + z;
}
Again - since all three structures are identical, it doesn't matter
which one you convert to.
int main()
{
void *x;
x = malloc (sizeof (struct tag_pc));
f1(x, 1);
Does that compile? Your function is declared to take three parameters.
I find f1() very redundant, and bulky, wouldn't you agree?
Not my version of it, no. Speaking of redundant - the redundancy began
when you declared three different structures with identical members, so
I don't think you have standing to complain about it now. What purpose
was that supposed to achieve, anyway?
Igor, I am looking for an alternative, and gentlemen in this post have
listed the alternatives
And you wouldn't take the alternative I've proposed because you don't
consider me a gentleman, I suppose.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-08-30 12:04:01 UTC
Permalink
Hello Igor,
Post by Igor Tandetnik
Why? Are you being charged per line of code?
The code in the function below really doesn't mean much but its just to
illustrate that keeping the cast(s) doesn't get rid of the redundance in the
f1() function. I showed an example below where suppose I have more code
residing in f1(), keeping the casts don't solve the problem. I understand the
part about the casts, but am I supposed to end up with something like this
for all my functions?

============================
typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
} pc;

typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
} ab;

typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
} cd;

void f1(void *x, int type, int z)
{
int y;
pc *p = x;
ab *q =x;
cd *r =x;

switch(type)
{
case 1:
for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
break;

case 2:
for(y=0; y<100; y++)
{
if(y==z)
{
q->LK__F1 = y;
q->LK__F2 = (y+12);
}
q->h = y+z;
}
break;

case 2:
for(y=0; y<100; y++)
{
if(y==z)
{
r->LK__F1 = y;
r->LK__F2 = (y+12);
}
r->h = y+z;
}
break;
}
}

int main()
{
void *x;

x = malloc (sizeof (struct tag_pc));
f1(x, 1);

x = malloc (sizeof (struct tag_ab));
f1(x, 2);

x = malloc (sizeof (struct tag_cd));
f1(x, 3);

free(x);
return 0;
}
===========================

I find f1() very redundant, and bulky, wouldn't you agree?
Igor, I am looking for an alternative, and gentlemen in this post have
listed the alternatives whereby the way I see it, asides from what was
proposed, theres not much more I can do becuase its C.

Thanks all for your help!
--
Best regards
Roberto
Post by Igor Tandetnik
Post by Robby
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
}
*but then* How do I know what pointer *type* is comming in the function ???
Since all the structures are layout-compatible, it doesn't really
matter. LK__F1 is the same size and at the same offset in all three
structures, so the assignment would work the same regardless of
which of the three types you cast to. Your code should work as
written.
Yes, but I wanted to get away with writting the above function
Post by Robby
pc *p = x;
Why? Are you being charged per line of code?
Post by Robby
But in C we can't. Unless I don't understand what you mean.
"Your code should work as written" sounds pretty unambiguous to me.
Post by Robby
//pc *p = x;
Well, not a cast, but there's a conversion (once you remove two slashes
in front so that it's not just a comment). In C++, such a conversion
would in fact require an explicit cast, but in C it happens implicitly.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
David Wilkinson
2009-08-30 17:49:04 UTC
Permalink
Post by Robby
Hello Igor,
Post by Igor Tandetnik
Why? Are you being charged per line of code?
The code in the function below really doesn't mean much but its just to
illustrate that keeping the cast(s) doesn't get rid of the redundance in the
f1() function. I showed an example below where suppose I have more code
residing in f1(), keeping the casts don't solve the problem. I understand the
part about the casts, but am I supposed to end up with something like this
for all my functions?
============================
typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
} pc;
typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
} ab;
typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
} cd;
void f1(void *x, int type, int z)
{
int y;
pc *p = x;
ab *q =x;
cd *r =x;
switch(type)
{
for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
q->LK__F1 = y;
q->LK__F2 = (y+12);
}
q->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
r->LK__F1 = y;
r->LK__F2 = (y+12);
}
r->h = y+z;
}
break;
}
}
int main()
{
void *x;
x = malloc (sizeof (struct tag_pc));
f1(x, 1);
x = malloc (sizeof (struct tag_ab));
f1(x, 2);
x = malloc (sizeof (struct tag_cd));
f1(x, 3);
free(x);
return 0;
}
===========================
I find f1() very redundant, and bulky, wouldn't you agree?
Igor, I am looking for an alternative, and gentlemen in this post have
listed the alternatives whereby the way I see it, asides from what was
proposed, theres not much more I can do becuase its C.
Thanks all for your help!
Robby:

As Igor says, since your three structures seem to be identical:

(a) there doesn't seem much point to having three of them

(b) it doesn't matter which one you cast the void* to, so you only need one
version of the function.

But to make it a bit more interesting, suppose the structures were different,
but with some common elements that you put at the beginning:

typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
// other pc stuff
} pc;

typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
// other ab stuff
} ab;

typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
// other cd stuff
} cd;

Then you might do

typedef struct tag_base {
long LK__F1;
long LK__F2;
long h;
} base;

void f1(void *x, int z)
{
int y;
base *p = x;

for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
}

This will work because pc, ab, cd and base all have the same layout for their
common elements.

The struct base is not really necessary (you could cast to one of the other
types, but it makes the solution more symmetric between the types.

In C++ you could derive pc, ab and cd from base and pass a base* instead of a
void*. (You could also use templates as Alex suggested). In C++ it is very
rarely necessary to "cheat" the type system, but it can often save a lot of
effort in C.
--
David Wilkinson
Visual C++ MVP
Robby
2009-08-31 16:54:01 UTC
Permalink
Hello David,

The reason I don't quite see it, is because what I am doing in my app is
slightly different than my sample I have posted. Let me get a liitle closer
to what I am doing in my app.

Now, I wrote the following sample on the fly without compiling it, and there
could be errors although what is important here is to give you an idea of the
mechanics I am confused about and what I am trying to do.

Bare in mind, still this is not the way I have it line for line in my app,
but its a little closer and rectifying this would greatly help.

=================================
typedef struct tag_lb_table
{ long LKdct__F1;}lb_table;

typedef struct tag_ab_table
{ long LKdct__F1;}ab_table;

typedef struct tag_ab_table
{ long LKdct__F1;}cd_table;

//============================
typedef struct tag_pc {
long LK__F1;
struct tag_pc_table *dc; // Pointer to an array of tag_pc_table structs
} pc;

typedef struct tag_ab {
long LK__F1;
struct tag_ab_table *dc; // Pointer to an array of tag_ab_table structs
} ab;

typedef struct tag_cd {
long LK__F1;
struct tag_cd_table *dc; // Pointer to an array of tag_cd_table structs
} cd;

void f1(void *x, int type)
{
pc *p = x;
ab *q = x;
cd *r = x;

switch(type)
{
case 1: p->LK__F1 = 10; p->dc[0].LKdct__F1 = 20; break;
case 2: q->LK__F1 = 10; q->dc[0].LKdct__F1 = 20; break;
case 3: r->LK__F1 = 10; r->dc[0].LKdct__F1 = 20; break;
}
}

int main()
{
void *x;

lb_table alb[] = { 100, 200};
ab_table aab[] = { 101, 201};
cd_table acd[] = { 102, 202};

x = malloc (sizeof (struct tag_pc));
x->dc = alb;
f1(x, 1);

x = malloc (sizeof (struct tag_ab));
x->dc = aab;
f1(x, 2);

x = malloc (sizeof (struct tag_cd));
x->dc = acd;
f1(x, 3);

free(x);
return 0;
}
===========================

So how would I do a base structure for the 3 structs above (tag_pc, tag_ab
and tag_cd) given this scenario?

Here in f1(), I had to cast every possible type and put it through a
switch/case statement, which is what I am trying to get rid of. But if I want
to get rid of the casts
how would f1() know what type we are passing in so it accesses
the correct array of structs for the following line:

p->dc[0].LKdct__F1 = 20;

Note, if the code shown in f1() would be the only code that f1() in my app
contained, well it would be accpetable to do it the way I showed it here. But
f1() has many more lines.

David, sorry for being confused!

Thanks for replying!
--
Best regards
Roberto
Post by David Wilkinson
Post by Robby
Hello Igor,
Post by Igor Tandetnik
Why? Are you being charged per line of code?
The code in the function below really doesn't mean much but its just to
illustrate that keeping the cast(s) doesn't get rid of the redundance in the
f1() function. I showed an example below where suppose I have more code
residing in f1(), keeping the casts don't solve the problem. I understand the
part about the casts, but am I supposed to end up with something like this
for all my functions?
============================
typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
} pc;
typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
} ab;
typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
} cd;
void f1(void *x, int type, int z)
{
int y;
pc *p = x;
ab *q =x;
cd *r =x;
switch(type)
{
for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
q->LK__F1 = y;
q->LK__F2 = (y+12);
}
q->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
r->LK__F1 = y;
r->LK__F2 = (y+12);
}
r->h = y+z;
}
break;
}
}
int main()
{
void *x;
x = malloc (sizeof (struct tag_pc));
f1(x, 1);
x = malloc (sizeof (struct tag_ab));
f1(x, 2);
x = malloc (sizeof (struct tag_cd));
f1(x, 3);
free(x);
return 0;
}
===========================
I find f1() very redundant, and bulky, wouldn't you agree?
Igor, I am looking for an alternative, and gentlemen in this post have
listed the alternatives whereby the way I see it, asides from what was
proposed, theres not much more I can do becuase its C.
Thanks all for your help!
(a) there doesn't seem much point to having three of them
(b) it doesn't matter which one you cast the void* to, so you only need one
version of the function.
But to make it a bit more interesting, suppose the structures were different,
typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
// other pc stuff
} pc;
typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
// other ab stuff
} ab;
typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
// other cd stuff
} cd;
Then you might do
typedef struct tag_base {
long LK__F1;
long LK__F2;
long h;
} base;
void f1(void *x, int z)
{
int y;
base *p = x;
for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
}
This will work because pc, ab, cd and base all have the same layout for their
common elements.
The struct base is not really necessary (you could cast to one of the other
types, but it makes the solution more symmetric between the types.
In C++ you could derive pc, ab and cd from base and pass a base* instead of a
void*. (You could also use templates as Alex suggested). In C++ it is very
rarely necessary to "cheat" the type system, but it can often save a lot of
effort in C.
--
David Wilkinson
Visual C++ MVP
Igor Tandetnik
2009-08-31 20:16:28 UTC
Permalink
Post by Robby
Bare in mind
What a disturbing image. Though I suppose "bear in mind" is not much
better. Now I'm going to have nightmares involving clean-shaved bears.
Post by Robby
=================================
typedef struct tag_lb_table
{ long LKdct__F1;}lb_table;
typedef struct tag_ab_table
{ long LKdct__F1;}ab_table;
typedef struct tag_ab_table
{ long LKdct__F1;}cd_table;
These three structs are still identical. Why again are you having three
of them?
Post by Robby
//============================
typedef struct tag_pc {
long LK__F1;
struct tag_pc_table *dc; // Pointer to an array of tag_pc_table
structs } pc;
typedef struct tag_ab {
long LK__F1;
struct tag_ab_table *dc; // Pointer to an array of tag_ab_table
structs } ab;
typedef struct tag_cd {
long LK__F1;
struct tag_cd_table *dc; // Pointer to an array of tag_cd_table
structs } cd;
And three more nearly identical structs. Why, oh why?
Post by Robby
void f1(void *x, int type)
{
pc *p = x;
ab *q = x;
cd *r = x;
switch(type)
{
case 1: p->LK__F1 = 10; p->dc[0].LKdct__F1 = 20; break;
case 2: q->LK__F1 = 10; q->dc[0].LKdct__F1 = 20; break;
case 3: r->LK__F1 = 10; r->dc[0].LKdct__F1 = 20; break;
}
}
Just make it

void f1(void *x)
{
pc *p = x;

p->LK__F1 = 10;
p->dc[0].LKdct__F1 = 20;
}
Post by Robby
int main()
{
void *x;
lb_table alb[] = { 100, 200};
ab_table aab[] = { 101, 201};
cd_table acd[] = { 102, 202};
x = malloc (sizeof (struct tag_pc));
x->dc = alb;
f1(x, 1);
x = malloc (sizeof (struct tag_ab));
x->dc = aab;
f1(x, 2);
x = malloc (sizeof (struct tag_cd));
x->dc = acd;
f1(x, 3);
free(x);
Note that you have three calls to malloc(), but only one call to free().
You are leaking two blocks of memory.
Post by Robby
So how would I do a base structure for the 3 structs above (tag_pc,
tag_ab and tag_cd) given this scenario?
I say you get rid of three identical structures, and declare just one.
Post by Robby
Here in f1(), I had to cast every possible type and put it through a
switch/case statement, which is what I am trying to get rid of. But
if I want to get rid of the casts
how would f1() know what type we are passing in so it accesses
p->dc[0].LKdct__F1 = 20;
Why would it care? They all have the same layout.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-09-01 04:32:06 UTC
Permalink
Hello Igor,
Post by Igor Tandetnik
These three structs are still identical. Why again are you having three
of them?
Because the actual 3 structures in my real code are really:
===========================================#1
typedef struct tag_pc_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
long e__pc_xchoice[PC_XCHO];
long e__pc_root_field[PC_ROOT];
int e__field1[PC_DF1];
int e__field2[PC_DF2];
int e__field3[PC_DF3];
int e__field4[PC_DF4];
long list_id;
char next_wnd_proc[PC_FWP][CHARS_MAX];
}pc_table;

============================================#2
typedef struct tag_ddlb_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
short quit_flag;
long message;
int l_mbs;
int h_mbe;
long e__ddlb_xchoice[DDLB_XCHO];
long ddlb_root_field[DDLB_ROOT];
long *e__ll;
int list_id;
long long_list_lenght;
int fwp[3];
char next_wnd_proc[DDLB_FWP][CHARS_MAX];
} ddlb_table;

====================================#3
typedef struct tag_lb_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
long TITLE;
int Q_MBS;
int Q_MBE;
long e__lb_xchoice[LB_XCHO];
long lb_root_field[LB_ROOT];
long e__field1[LB_DF1];
long lb_field2[LB_DF2];
long *e__ll;
long list_id;
long long_list_lenght;
char next_wnd_proc[LB_FWP][CHARS_MAX];
}lb_table;

Unless I am totally out of it, I don't think they are all 3 identical!
Post by Igor Tandetnik
And three more nearly identical structs. Why, oh why?
Because again, these other 3 structures in my real code, are really:

=========================================#1
typedef struct tag_pc {
long gso_eeprom_address;
int gso_arr_address;
short pc_entry_mode;
long LK__F1;
long LK__F2;
long LK__F3;
int digits;
struct tag_pc_table *dc;
int dc_size;
int x_start_pos;
int y_start_pos;
int y_end_pos;
int char_mask_intrvl;
int msg_char_mask;
int sys__tot_itms_in_list;
int sys__list_item_idx;
long sys__curr_fwp_idx;
long sys__exodus;
} pc;

========================================#2
typedef struct tag_ddlb
{
long gso_eeprom_address;
int gso_arr_address;
long LK__F1;
long LK__F2;
long LK__F3;
long dc_size;
struct tag_ddlb_table *dc;
long sys_question_idx;
int sys__tot_itms_in_list;
int sys__list_item_idx;
int sys__ddlb_state_flag;
long sys__curr_fwp_idx;
long sys__exodus;
} ddlb;

========================================#3

typedef struct tag_lb
{
long gso_eeprom_address;
int gso_arr_address;
short menu_entry_mode;
long LK__F1;
long LK__F2;
long LK__F3;
struct tag_lb_table *dc;
long dc_size;
long *pmr;
long pmr_row;
long pmr_col;
int sys__tot_itms_in_list;
int sys__list_item_idx;
long sys__selected_pmr;
long sys__curr_fwp_idx;
long sys__exodus;
}lb;
===========================================

So, now what! Do we still feel that this would work:

void f1(void *x)
{
pc *p = x;

p->LK__F1 = 10;
p->dc[0].LKdct__F1 = 20;
}

Igor, perhaps you are right as you usually are, but, I don't see how f1()
can access its respective members from the correct structure by simply doing
one cast as you show it above? Don't get me wrong here, I am not going
against you, its just that I sincerely don't see it.

Look, if I do this:

======================================
int main()
{
void *x;

pc_table apc[] = { 101, 201...............}; // Innitialize all members here
ddlb_table addlb[] = { 102, 202.........}; // Innitialize all members here
lb_table alb[] = { 123, 200................}; // Innitialize all members here

x = malloc (sizeof (struct tag_lb));
x->dc = alb;
f1(x, 2);
=========================================

And for instance, if in f1() we have the only cast as so:

pc *p = x;

how is f1() ever going to get the value of Q_MBS which is in the
lb_table.... notice that Q_MBS does not exist in pc_table! So therefore
various casts have to exist in
f1() and based on what we pass in as the x parameter of F1() we have to
execute the correct cast... no?

I don't know, maybe its me! Theres something I don't understand.
Post by Igor Tandetnik
Note that you have three calls to malloc(), but only one call to free().
You are leaking two blocks of memory.
I know, I know.
--
Best regards
Roberto
Post by Igor Tandetnik
Post by Robby
Bare in mind
What a disturbing image. Though I suppose "bear in mind" is not much
better. Now I'm going to have nightmares involving clean-shaved bears.
Post by Robby
=================================
typedef struct tag_lb_table
{ long LKdct__F1;}lb_table;
typedef struct tag_ab_table
{ long LKdct__F1;}ab_table;
typedef struct tag_ab_table
{ long LKdct__F1;}cd_table;
These three structs are still identical. Why again are you having three
of them?
Post by Robby
//============================
typedef struct tag_pc {
long LK__F1;
struct tag_pc_table *dc; // Pointer to an array of tag_pc_table
structs } pc;
typedef struct tag_ab {
long LK__F1;
struct tag_ab_table *dc; // Pointer to an array of tag_ab_table
structs } ab;
typedef struct tag_cd {
long LK__F1;
struct tag_cd_table *dc; // Pointer to an array of tag_cd_table
structs } cd;
And three more nearly identical structs. Why, oh why?
Post by Robby
void f1(void *x, int type)
{
pc *p = x;
ab *q = x;
cd *r = x;
switch(type)
{
case 1: p->LK__F1 = 10; p->dc[0].LKdct__F1 = 20; break;
case 2: q->LK__F1 = 10; q->dc[0].LKdct__F1 = 20; break;
case 3: r->LK__F1 = 10; r->dc[0].LKdct__F1 = 20; break;
}
}
Just make it
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
p->dc[0].LKdct__F1 = 20;
}
Post by Robby
int main()
{
void *x;
lb_table alb[] = { 100, 200};
ab_table aab[] = { 101, 201};
cd_table acd[] = { 102, 202};
x = malloc (sizeof (struct tag_pc));
x->dc = alb;
f1(x, 1);
x = malloc (sizeof (struct tag_ab));
x->dc = aab;
f1(x, 2);
x = malloc (sizeof (struct tag_cd));
x->dc = acd;
f1(x, 3);
free(x);
Note that you have three calls to malloc(), but only one call to free().
You are leaking two blocks of memory.
Post by Robby
So how would I do a base structure for the 3 structs above (tag_pc,
tag_ab and tag_cd) given this scenario?
I say you get rid of three identical structures, and declare just one.
Post by Robby
Here in f1(), I had to cast every possible type and put it through a
switch/case statement, which is what I am trying to get rid of. But
if I want to get rid of the casts
how would f1() know what type we are passing in so it accesses
p->dc[0].LKdct__F1 = 20;
Why would it care? They all have the same layout.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Ulrich Eckhardt
2009-09-01 08:27:20 UTC
Permalink
Post by Robby
Post by Igor Tandetnik
These three structs are still identical. Why again are you having three
of them?
===========================================#1
typedef struct tag_pc_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
[...stuff...]
Post by Robby
}pc_table;
============================================#2
typedef struct tag_ddlb_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
[...other stuff...]
Post by Robby
} ddlb_table;
====================================#3
typedef struct tag_lb_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
[...more stuff...]
Post by Robby
}lb_table;
Unless I am totally out of it, I don't think they are all 3 identical!
Yeah, well, I hope you learn to not omit important details from your
examples.

Anyhow: The three share the same three initial members. You could factor out
a single base structure to use as first member and access them using this
base structure as type.
Post by Robby
Post by Igor Tandetnik
And three more nearly identical structs. Why, oh why?
[three different structs, each containing a pointer/size combo to hold an
array of the above]
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
Since 'pc' and the other two don't have LK__F1 [0] as common initial member,
this code doesn't work.
Post by Robby
p->dc[0].LKdct__F1 = 20;
Note that while you can address the initial three members of the table
structs via any pointer to them, indexing into an array requires knowledge
of the size of the exact type, so this doesn't automatically work.
Post by Robby
Igor, perhaps you are right as you usually are, but, I don't see how f1()
can access its respective members from the correct structure by simply
doing one cast as you show it above? Don't get me wrong here, I am not
going against you, its just that I sincerely don't see it.
You are right, it doesn't work. Now that you have shown the fill information
it is obvious that it doesn't work.

Some suggestions:
1. You could use a union type to store the array and store the array in the
initial members of the struct, so that you can factor out a base-struct
that contains the pointer/size_t combo.
2. You could also attach the type to the struct itself, like in the first
member an enumeration. This would allow you to distinguish the type easier.
You could then treat the void pointer as pointer to the enumeration, read
it, and then treat the different types accordingly.
3. You could also attach a function-pointer for various things that have
common behaviour but actually different implementations for different
types.


Up to now, there doesn't seem to be an easy way out.

Uli

[0] It is common agreement that using ALL_UPPERCASE should be left to
macros. It is a requirement of the standard that you don't use any names
with TWO__CONSECUTIVE underscores. Your program is technically ill-formed.
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Igor Tandetnik
2009-09-01 12:10:07 UTC
Permalink
Post by Ulrich Eckhardt
1. You could use a union type to store the array and store the array
in the initial members of the struct, so that you can factor out a
base-struct that contains the pointer/size_t combo.
2. You could also attach the type to the struct itself, like in the
first member an enumeration. This would allow you to distinguish the
type easier. You could then treat the void pointer as pointer to the
enumeration, read it, and then treat the different types accordingly.
3. You could also attach a function-pointer for various things that
have common behaviour but actually different implementations for
different types.
4. Since the only thing these structs have in common is an accident of
having members with the same name, you could use a macro in place of a
function:

#define f(p) \
do { \
(p)->LK__F1 = 10; \
(p)->dc[0].LKdct__F1 = 20; \
} while (0)

But give your macro some long and ugly name other than "f".
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-09-01 14:40:01 UTC
Permalink
Hello Igor,
Post by Igor Tandetnik
#define f(p) \
do { \
(p)->LK__F1 = 10; \
(p)->dc[0].LKdct__F1 = 20; \
} while (0)
Although the above is a solution, you have to realize that many of the f1()
functions
that I have are between 50 and 100 lines long. And I don't know if it would
be appropriate to have such large #define macro functions.

I don't know, I will have to think about it.

Thanks for your help.
--
Best regards
Roberto
Post by Igor Tandetnik
Post by Ulrich Eckhardt
1. You could use a union type to store the array and store the array
in the initial members of the struct, so that you can factor out a
base-struct that contains the pointer/size_t combo.
2. You could also attach the type to the struct itself, like in the
first member an enumeration. This would allow you to distinguish the
type easier. You could then treat the void pointer as pointer to the
enumeration, read it, and then treat the different types accordingly.
3. You could also attach a function-pointer for various things that
have common behaviour but actually different implementations for
different types.
4. Since the only thing these structs have in common is an accident of
having members with the same name, you could use a macro in place of a
#define f(p) \
do { \
(p)->LK__F1 = 10; \
(p)->dc[0].LKdct__F1 = 20; \
} while (0)
But give your macro some long and ugly name other than "f".
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Igor Tandetnik
2009-09-01 16:53:22 UTC
Permalink
Post by Robby
Hello Igor,
Post by Igor Tandetnik
#define f(p) \
do { \
(p)->LK__F1 = 10; \
(p)->dc[0].LKdct__F1 = 20; \
} while (0)
Although the above is a solution, you have to realize that many of
the f1() functions
that I have are between 50 and 100 lines long. And I don't know if it
would be appropriate to have such large #define macro functions.
How about this:

void RealF(long* pLK__F1, long* LKdct__F1) {
*pLK__F1 = 10;
*LKdct__F1 = 20;
// Whatever other work you need to do on the common members of these
structs
}

#define f(p) RealF(&((p)->LK__F1), &((p)->dc[0].LKdct__F1))
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-09-01 17:43:02 UTC
Permalink
Hello Igor,

I really seem to be stuck on this one. I did alot of functions with
repetitive code with only the *type* of pointer as different and said to
myself that I would clean these functions up and create one function for
every group of similar functions. And now, I think I shot myself in the foot.
I am sooooo dis..cou..rag..ed !

Hmmm! okay.... :-)
Post by Igor Tandetnik
void RealF(long* pLK__F1, long* LKdct__F1) {
*pLK__F1 = 10;
*LKdct__F1 = 20;
// Whatever other work you need to do on the common members of these structs
}
#define f(p) RealF(&((p)->LK__F1), &((p)->dc[0].LKdct__F1))
That's what I like about you, you always find a way ! And Igor, I sincerely
would wish that this would be the solution for me... honestly, your sample
amazes me, because I would of never thought of it this way.... but
unfortunately, I will have to show you one of my reall dilemas by posting one
of the actual functions. The function you are about to see, is repeated 3
times in my application. I really would love to just have one version of it
and burry it somewhare in my libraries and forget about it. The only
difference between the 3 functions is the type of pointer to the structure
that is passed in...that's all! very similar to what we have been posting in
the las 20 some odd postings of this thread.

Just a quick note in case you would ask, LNUL simply stands for "linking
null" and is defined as a large value as so: #define LNUL 55555, and is never
used for the linking fileds. So if any fileds are set to LNUL, then we know
that the coresponding field is not used as a table linking field.

So, here it goes.... :-(

=========================================

int lb_match_link_id (lb *pObj)
{

// *** VARIABLES *** //

long i;
int recIdxFields;

// *** DO TABLE LINKING OPERATIONS *** //

if (pObj->LK__F1 == LNUL && pObj->LK__F2 == LNUL && pObj->LK__F3 == LNUL)
// No likning required.
recIdxFields = 0;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 == LNUL && pObj->LK__F3 ==
LNUL) // One linking field required
recIdxFields = 1;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 != LNUL && pObj->LK__F3 ==
LNUL) // Two linking fields required
recIdxFields = 2;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 != LNUL && pObj->LK__F3 !=
LNUL) // Three linking fields required
recIdxFields = 3;

for(i=0; i<(pObj->dc_size); i++)
{
switch(recIdxFields)
{
case 1:
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 ) // Test one linking field
{
return i;
}
break;

case 2:
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 && // Test two linking fields
pObj->dc[i].LKdct__F2 == pObj->LK__F2)
{
return i;
}
break;

case 3:
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 && // Test three linking fields
pObj->dc[i].LKdct__F2 == pObj->LK__F2 &&
pObj->dc[i].LKdct__F3 == pObj->LK__F3 )
{
return i;
}
break;

default:
return 0;
break;
}
}
}
===========================================

I really didn't want to get to this point where I have to show so much
code... I appolagize to you and to everyone else. But, not being able to
condense repetitive code, to me, is a serious problem.

So, I see your sample above is quite brilliant (to me anyways) but how am I
supposed to use it taking into account all the logic that has to be done in
my function I just posted?

Isn't there a way to just cast the pointer to a desired type after we start
doing some logic? I have been trying here for hours... all sorts of tests and
C is so particular to its types being placed at the top of any routine that I
see no way out!

oooff!

Thanks for your continous help Igor!
I will take a better look at your sample and go form there!
--
Best regards
Roberto
Post by Igor Tandetnik
Post by Robby
Hello Igor,
Post by Igor Tandetnik
#define f(p) \
do { \
(p)->LK__F1 = 10; \
(p)->dc[0].LKdct__F1 = 20; \
} while (0)
Although the above is a solution, you have to realize that many of
the f1() functions
that I have are between 50 and 100 lines long. And I don't know if it
would be appropriate to have such large #define macro functions.
void RealF(long* pLK__F1, long* LKdct__F1) {
*pLK__F1 = 10;
*LKdct__F1 = 20;
// Whatever other work you need to do on the common members of these
structs
}
#define f(p) RealF(&((p)->LK__F1), &((p)->dc[0].LKdct__F1))
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Igor Tandetnik
2009-09-01 18:46:31 UTC
Permalink
Post by Robby
int lb_match_link_id (lb *pObj)
{
// *** VARIABLES *** //
long i;
int recIdxFields;
// *** DO TABLE LINKING OPERATIONS *** //
if (pObj->LK__F1 == LNUL && pObj->LK__F2 == LNUL && pObj->LK__F3 ==
LNUL) // No likning required.
recIdxFields = 0;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 == LNUL && pObj->LK__F3
== LNUL) // One linking field required
recIdxFields = 1;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 != LNUL && pObj->LK__F3
== LNUL) // Two linking fields required
recIdxFields = 2;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 != LNUL && pObj->LK__F3
!= LNUL) // Three linking fields required
recIdxFields = 3;
for(i=0; i<(pObj->dc_size); i++)
{
switch(recIdxFields)
{
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 ) // Test one linking
field {
return i;
}
break;
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 && // Test two linking
fields pObj->dc[i].LKdct__F2 == pObj->LK__F2)
{
return i;
}
break;
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 && // Test three linking
fields pObj->dc[i].LKdct__F2 == pObj->LK__F2 &&
pObj->dc[i].LKdct__F3 == pObj->LK__F3 )
{
return i;
}
break;
return 0;
break;
}
}
}
This is going to be ugly, but your awkward struct layout leaves little
choice:

struct ThreeLinks {
long LK1;
long LK2;
long LK3;
};

int REAL_match_link_id(ThreeLinks* find_what, ThreeLinks* table, int
table_size, int table_elem_size)
{
int i;
for(i = 0; i < table_size; i++) {
ThreeLinks* elem = (ThreeLinks*)( (char*) table + i *
table_elem_size);
if ( (find_what->LK1 == LNUL || find_what->LK1 == elem->LK1) &&
(find_what->LK2 == LNUL || find_what->LK2 == elem->LK2) &&
(find_what->LK3 == LNUL || find_what->LK3 == elem->LK3)) {
return i;
}
}
return 0;
}

#define match_link_id(pObj) \
REAL_match_link_id( \
(ThreeLinks*) &((pObj)->LK__F1), \
(ThreeLinks*) &((pObj)->dc[0].LKdct__F1), \
(pObj)->dc_size, \
sizeof((pObj)->dc[0]) )
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-09-01 20:11:01 UTC
Permalink
Hey Igor!
Post by Igor Tandetnik
This is going to be ugly, but your awkward struct layout leaves little
I'd say "Bruta comme la fame" :-) means "ugly like hunger" in Italian. It
sounds better when we say it in Italian though. Jokes aside, Igor, I thankyou
very much for your effort, that was very nice of you. It looks quite
complicated at first glance... I don't quite get what the "(char*)" is doing
there, although it is a valid solution. This would also require me to alter
some of the code in the function(s) at the risk of other things going wrong
leaving me with potential delays.

I was looking more for a way to leave all function's code exactly the way it
is and do a simple pointer type casting manouver, but as this post reveals
there is no simple solution. In C , the type is the type and that's that!

Your solution is great, but if I do start altering code in functions of my
application, too much can go wrong... geeze , sometimes I just rename a
variable and nothing works anymore.

I have explored this issue in this thread and I think I will leave
everything the way it is and when I re-write the program in C++, I will use
templates to condense code. I think this will be alot easier... I guess!

Again, I thankyou very much for your time, and help. I also thank everyone
else that contributed to this thread/question.

PS Igor, your sample is still well worth the post as I did learn a few
things from it anyway! :-)
--
Best regards
Roberto
Post by Igor Tandetnik
Post by Robby
int lb_match_link_id (lb *pObj)
{
// *** VARIABLES *** //
long i;
int recIdxFields;
// *** DO TABLE LINKING OPERATIONS *** //
if (pObj->LK__F1 == LNUL && pObj->LK__F2 == LNUL && pObj->LK__F3 ==
LNUL) // No likning required.
recIdxFields = 0;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 == LNUL && pObj->LK__F3
== LNUL) // One linking field required
recIdxFields = 1;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 != LNUL && pObj->LK__F3
== LNUL) // Two linking fields required
recIdxFields = 2;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 != LNUL && pObj->LK__F3
!= LNUL) // Three linking fields required
recIdxFields = 3;
for(i=0; i<(pObj->dc_size); i++)
{
switch(recIdxFields)
{
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 ) // Test one linking
field {
return i;
}
break;
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 && // Test two linking
fields pObj->dc[i].LKdct__F2 == pObj->LK__F2)
{
return i;
}
break;
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 && // Test three linking
fields pObj->dc[i].LKdct__F2 == pObj->LK__F2 &&
pObj->dc[i].LKdct__F3 == pObj->LK__F3 )
{
return i;
}
break;
return 0;
break;
}
}
}
This is going to be ugly, but your awkward struct layout leaves little
struct ThreeLinks {
long LK1;
long LK2;
long LK3;
};
int REAL_match_link_id(ThreeLinks* find_what, ThreeLinks* table, int
table_size, int table_elem_size)
{
int i;
for(i = 0; i < table_size; i++) {
ThreeLinks* elem = (ThreeLinks*)( (char*) table + i *
table_elem_size);
if ( (find_what->LK1 == LNUL || find_what->LK1 == elem->LK1) &&
(find_what->LK2 == LNUL || find_what->LK2 == elem->LK2) &&
(find_what->LK3 == LNUL || find_what->LK3 == elem->LK3)) {
return i;
}
}
return 0;
}
#define match_link_id(pObj) \
REAL_match_link_id( \
(ThreeLinks*) &((pObj)->LK__F1), \
(ThreeLinks*) &((pObj)->dc[0].LKdct__F1), \
(pObj)->dc_size, \
sizeof((pObj)->dc[0]) )
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-09-02 03:13:01 UTC
Permalink
One more thing which is of concern,

As Alex as pointed out the following:

==========================================
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
}
==========================================

So, if I would switch from C to C++, would the following solve the problem
if I used templates like this:

===========================================
template<typename T>
void f1(T* p)
{
p->LK__F1 = 10;
p->dc[0].LKdct__F1 = 20;
}
===========================================

In other words using templates, would allow me to keep all my functions
exactly the way there are right?

Just want to make sure that if I do such a move it will relevant to solving
this issue.
--
Best regards
Roberto
Post by Igor Tandetnik
Post by Robby
int lb_match_link_id (lb *pObj)
{
// *** VARIABLES *** //
long i;
int recIdxFields;
// *** DO TABLE LINKING OPERATIONS *** //
if (pObj->LK__F1 == LNUL && pObj->LK__F2 == LNUL && pObj->LK__F3 ==
LNUL) // No likning required.
recIdxFields = 0;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 == LNUL && pObj->LK__F3
== LNUL) // One linking field required
recIdxFields = 1;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 != LNUL && pObj->LK__F3
== LNUL) // Two linking fields required
recIdxFields = 2;
else if (pObj->LK__F1 != LNUL && pObj->LK__F2 != LNUL && pObj->LK__F3
!= LNUL) // Three linking fields required
recIdxFields = 3;
for(i=0; i<(pObj->dc_size); i++)
{
switch(recIdxFields)
{
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 ) // Test one linking
field {
return i;
}
break;
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 && // Test two linking
fields pObj->dc[i].LKdct__F2 == pObj->LK__F2)
{
return i;
}
break;
if(pObj->dc[i].LKdct__F1 == pObj->LK__F1 && // Test three linking
fields pObj->dc[i].LKdct__F2 == pObj->LK__F2 &&
pObj->dc[i].LKdct__F3 == pObj->LK__F3 )
{
return i;
}
break;
return 0;
break;
}
}
}
This is going to be ugly, but your awkward struct layout leaves little
struct ThreeLinks {
long LK1;
long LK2;
long LK3;
};
int REAL_match_link_id(ThreeLinks* find_what, ThreeLinks* table, int
table_size, int table_elem_size)
{
int i;
for(i = 0; i < table_size; i++) {
ThreeLinks* elem = (ThreeLinks*)( (char*) table + i *
table_elem_size);
if ( (find_what->LK1 == LNUL || find_what->LK1 == elem->LK1) &&
(find_what->LK2 == LNUL || find_what->LK2 == elem->LK2) &&
(find_what->LK3 == LNUL || find_what->LK3 == elem->LK3)) {
return i;
}
}
return 0;
}
#define match_link_id(pObj) \
REAL_match_link_id( \
(ThreeLinks*) &((pObj)->LK__F1), \
(ThreeLinks*) &((pObj)->dc[0].LKdct__F1), \
(pObj)->dc_size, \
sizeof((pObj)->dc[0]) )
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Robby
2009-09-01 14:50:03 UTC
Permalink
Hello Ulrich,
Post by Ulrich Eckhardt
2. You could also attach the type to the struct itself, like in the first
member an enumeration. This would allow you to distinguish the type easier.
You could then treat the void pointer as pointer to the enumeration, read
it, and then treat the different types accordingly.
This seems interesting, but I don't quite understand what you mean by:

"You could also attach the type to the struct itself, like in the first
member an enumeration."

I have never done this. Is it possible to show a very short example...
perhaps 5 lines or so, I would really appreciate it. If its too much trouble,
then its okay too.

Thankyou very much for your feedback.

I thank all who has responded to this post!
--
Best regards
Roberto
Post by Ulrich Eckhardt
Post by Robby
Post by Igor Tandetnik
These three structs are still identical. Why again are you having three
of them?
===========================================#1
typedef struct tag_pc_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
[...stuff...]
Post by Robby
}pc_table;
============================================#2
typedef struct tag_ddlb_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
[...other stuff...]
Post by Robby
} ddlb_table;
====================================#3
typedef struct tag_lb_table
{
long LKdct__F1;
long LKdct__F2;
long LKdct__F3;
[...more stuff...]
Post by Robby
}lb_table;
Unless I am totally out of it, I don't think they are all 3 identical!
Yeah, well, I hope you learn to not omit important details from your
examples.
Anyhow: The three share the same three initial members. You could factor out
a single base structure to use as first member and access them using this
base structure as type.
Post by Robby
Post by Igor Tandetnik
And three more nearly identical structs. Why, oh why?
[three different structs, each containing a pointer/size combo to hold an
array of the above]
Post by Robby
void f1(void *x)
{
pc *p = x;
p->LK__F1 = 10;
Since 'pc' and the other two don't have LK__F1 [0] as common initial member,
this code doesn't work.
Post by Robby
p->dc[0].LKdct__F1 = 20;
Note that while you can address the initial three members of the table
structs via any pointer to them, indexing into an array requires knowledge
of the size of the exact type, so this doesn't automatically work.
Post by Robby
Igor, perhaps you are right as you usually are, but, I don't see how f1()
can access its respective members from the correct structure by simply
doing one cast as you show it above? Don't get me wrong here, I am not
going against you, its just that I sincerely don't see it.
You are right, it doesn't work. Now that you have shown the fill information
it is obvious that it doesn't work.
1. You could use a union type to store the array and store the array in the
initial members of the struct, so that you can factor out a base-struct
that contains the pointer/size_t combo.
2. You could also attach the type to the struct itself, like in the first
member an enumeration. This would allow you to distinguish the type easier.
You could then treat the void pointer as pointer to the enumeration, read
it, and then treat the different types accordingly.
3. You could also attach a function-pointer for various things that have
common behaviour but actually different implementations for different
types.
Up to now, there doesn't seem to be an easy way out.
Uli
[0] It is common agreement that using ALL_UPPERCASE should be left to
macros. It is a requirement of the standard that you don't use any names
with TWO__CONSECUTIVE underscores. Your program is technically ill-formed.
--
C++ FAQ: http://parashift.com/c++-faq-lite
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Ulrich Eckhardt
2009-09-02 07:47:44 UTC
Permalink
Post by Robby
Post by Ulrich Eckhardt
2. You could also attach the type to the struct itself, like in the first
member an enumeration. This would allow you to distinguish the type
easier. You could then treat the void pointer as pointer to the
enumeration, read it, and then treat the different types accordingly.
"You could also attach the type to the struct itself, like in the first
member an enumeration."
I have never done this. Is it possible to show a very short example...
perhaps 5 lines or so, I would really appreciate it. If its too much
trouble, then its okay too.
enum type {
type_pc,
type_ddlb,
};
struct pc {
enum type type;
...
};
struct ddlb {
enum type type;
...
};

void get_f1(void* p) {
enum type* t = p;
switch(*t) {
case type_pc: {
struct pc* pc = p;
return pc->f1;
}
break;
case type_ddlb: {
struct ddlb* ddlb = p;
return ddlb->f1;
}
break;
default:
assert(0);
}
}

Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Robby
2009-09-02 20:22:08 UTC
Permalink
Hello Uli,

Sorry for bothering you with the sample, that was very nice of you to take
time and get back with a sample code. It is very appreciated.

I have entered your solution in VC++ compiler to try it, but I do get the
following warning:

1>c:\_dts_programming\c_programming\c\c_tests\c_string_samples\misc_c_samples\enumpointer.c(59)
: warning C4715: 'get_f1' : not all control paths return a value

But before discussing the warning, I have a 2 questions and I will outline
them at the end of this post. In the mean time here is how I tried it, note I
typedefed my structs though:

================================

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum type {type_pc, type_ddlb};


// TABLES
typedef struct tag_pc_table
{
long z;
long h;
}pc_table;

typedef struct tag_lb_table
{
long z;
long u;
}lb_table;

// OBJECTS
typedef struct tag_pc {
long w;
struct tag_pc_table *dc;
enum type type;
} pc;

typedef struct tag_lb {
long w;
struct tag_lb_table *dc;
enum type type;
} lb;


void* get_f1(void* p)
{
enum type* t = p;

switch(*t)
{
case type_pc:
{
struct pc* pc = p;
return pc; //pc->f1;
}
break;

case type_ddlb:
{
struct ddlb* ddlb = p;
return ddlb; //ddlb->f1;
}
break;
}
}

int main()
{
long t;
pc *a;
lb *b;

pc_table apc[] = {101, 201, 301, 302}; // Fill table
lb_table alb[] = {102, 202, 401, 402}; // Fill table

a = malloc(sizeof (struct tag_pc));
get_f1(a);

b = malloc(sizeof (struct tag_lb));
get_f1(b);


free(a);
free(b);
return 0;
}
=================================

1- One thing I don't get is when I pass in the "a" variable when calling the
get_f1() function, its address gets assigned to *t byt he following line: in
the get_f1() function:

enum type* t = p;

and then we put *t in the switch command/case command, but the type_pc and
type_ddlb are 0, and 1 respectively and really don't match with (*t) ?

2- Why are we returning pc->f1, I don't think f1 is a member of the
structures?

3- What are we supposed to return? >>> pc or ddlb?

Anyhow, I have been experimenting with this and it turns out that you guys
were right that it works without implicitly casting to the correct type. I am
still scratching my head on that one as to why it would still work. I didn't
use any templates, macro functions or base structs. I will post the example
in a new post... this one has pretty well got its usage! The new post will be
called "No casting of void*"

Uli, I still am currious about the questions I asked here!

Thanks for your input!
--
Best regards
Roberto
Post by Ulrich Eckhardt
Post by Robby
Post by Ulrich Eckhardt
2. You could also attach the type to the struct itself, like in the first
member an enumeration. This would allow you to distinguish the type
easier. You could then treat the void pointer as pointer to the
enumeration, read it, and then treat the different types accordingly.
"You could also attach the type to the struct itself, like in the first
member an enumeration."
I have never done this. Is it possible to show a very short example...
perhaps 5 lines or so, I would really appreciate it. If its too much
trouble, then its okay too.
enum type {
type_pc,
type_ddlb,
};
struct pc {
enum type type;
...
};
struct ddlb {
enum type type;
...
};
void get_f1(void* p) {
enum type* t = p;
switch(*t) {
case type_pc: {
struct pc* pc = p;
return pc->f1;
}
break;
case type_ddlb: {
struct ddlb* ddlb = p;
return ddlb->f1;
}
break;
assert(0);
}
}
Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Ulrich Eckhardt
2009-09-03 06:42:42 UTC
Permalink
Post by Robby
enum type {type_pc, type_ddlb};
typedef struct tag_pc {
long w;
struct tag_pc_table *dc;
enum type type;
} pc;
Stop. Put the 'type' field at the first position of the struct. This is
important. Only then can you use a pointer to a 'struct tag_pc' like one
that points to an 'enum type'. Also, and that has been stressed here over
and over, you may only assume that the _initial_ and _equal_ elements of
two structures have the same layout, so that you can access them
interchangeably.
Post by Robby
a = malloc(sizeof (struct tag_pc));
get_f1(a);
You did not initialise the 'type' field with the correct value, so type
detection via this field can not work.

Uli
--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
Robby
2009-09-02 04:05:01 UTC
Permalink
Thankyou David,
--
Best regards
Roberto
Post by David Wilkinson
Post by Robby
Hello Igor,
Post by Igor Tandetnik
Why? Are you being charged per line of code?
The code in the function below really doesn't mean much but its just to
illustrate that keeping the cast(s) doesn't get rid of the redundance in the
f1() function. I showed an example below where suppose I have more code
residing in f1(), keeping the casts don't solve the problem. I understand the
part about the casts, but am I supposed to end up with something like this
for all my functions?
============================
typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
} pc;
typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
} ab;
typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
} cd;
void f1(void *x, int type, int z)
{
int y;
pc *p = x;
ab *q =x;
cd *r =x;
switch(type)
{
for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
q->LK__F1 = y;
q->LK__F2 = (y+12);
}
q->h = y+z;
}
break;
for(y=0; y<100; y++)
{
if(y==z)
{
r->LK__F1 = y;
r->LK__F2 = (y+12);
}
r->h = y+z;
}
break;
}
}
int main()
{
void *x;
x = malloc (sizeof (struct tag_pc));
f1(x, 1);
x = malloc (sizeof (struct tag_ab));
f1(x, 2);
x = malloc (sizeof (struct tag_cd));
f1(x, 3);
free(x);
return 0;
}
===========================
I find f1() very redundant, and bulky, wouldn't you agree?
Igor, I am looking for an alternative, and gentlemen in this post have
listed the alternatives whereby the way I see it, asides from what was
proposed, theres not much more I can do becuase its C.
Thanks all for your help!
(a) there doesn't seem much point to having three of them
(b) it doesn't matter which one you cast the void* to, so you only need one
version of the function.
But to make it a bit more interesting, suppose the structures were different,
typedef struct tag_pc {
long LK__F1;
long LK__F2;
long h;
// other pc stuff
} pc;
typedef struct tag_ab {
long LK__F1;
long LK__F2;
long h;
// other ab stuff
} ab;
typedef struct tag_cd {
long LK__F1;
long LK__F2;
long h;
// other cd stuff
} cd;
Then you might do
typedef struct tag_base {
long LK__F1;
long LK__F2;
long h;
} base;
void f1(void *x, int z)
{
int y;
base *p = x;
for(y=0; y<100; y++)
{
if(y==z)
{
p->LK__F1 = y;
p->LK__F2 = (y+12);
}
p->h = y+z;
}
}
This will work because pc, ab, cd and base all have the same layout for their
common elements.
The struct base is not really necessary (you could cast to one of the other
types, but it makes the solution more symmetric between the types.
In C++ you could derive pc, ab and cd from base and pass a base* instead of a
void*. (You could also use templates as Alex suggested). In C++ it is very
rarely necessary to "cheat" the type system, but it can often save a lot of
effort in C.
--
David Wilkinson
Visual C++ MVP
Continue reading on narkive:
Loading...