Jump to content

Error: Variable 'functionname' Already Exists


Recommended Posts

I am trying to integrate a C library into my project and came across a problem. This library was compiling ok in HI-TECH, so the syntax is ok with at least that compiler. Here's the problem:

 

The error in the subject line is generated when this line is in the code

 

BOOL( *functionname ) ( void );

 

It is a function pointer that is set in the code depending on what mode it's in. If I comment it out, it compiles, but fails at link saying:

 

Error: Failed to resolve external: functionname

 

BOOL is already defined elsewhere. I'm stumped. Any ideas?

Link to post
Share on other sites

Is it something like this you want ?

#include <system.h>
bool myfunc(void)
{
return true;
}
bool (*pFunc)(void);
char myvar;
void main()
{
pFunc = myfunc();
if (pFunc)
{
 myvar = 1;
}
else
{
 myvar = 2;
}

while (1);
}

 

Boolean is lower case bool or you can use bit.

 

Cheers

 

Reynard

Link to post
Share on other sites

Is it something like this you want ?

 

Boolean is lower case bool or you can use bit.

 

Cheers

 

Reynard

 

 

I tracked it down further. In the .c file I have:

 

BOOL( *functionname ) ( void );

 

In an included .h file, that function is extern'ed:

 

extern BOOL( *functionname ) ( void );

 

 

When both these are present, it complains: error: variable 'functionname' already exists

 

If I remove the "extern" line, that .c file compiles, but of course other .c files calling that function fail. Does BoostC use extern differently? Having an extern really shouldn't cause any problems. Even if I move the extern to the .c file in question, just to test, it still gives me the same "already exists" error.

 

 

EDIT: Just found that this problem was reported in 2004, but has no responses!

http://forum.sourceboost.com/index.php?showtopic=645

Edited by jrmymllr
Link to post
Share on other sites

Hi

 

I don't see that as an issue.

For me it looks like an error in program organization.

 

When a "C" file is parsed it can not find two definitions for the same symbol.

A declaration with an "extern" defines the symbol just like the main definition. The only difference is that it doesn't allocate program/memory room for it because its is done in a different module.

If in the parser path it finds both the declaration and the definition its still a double definition for the same object so its an error.

The "extern" declaration can't never be placed in the same parser path, diirectly or included, as the definition of the same object.

 

Probably what you need is to review the organization of your ".h" files and their inclusion, including nested inclusion, in the various "C" modules.

 

 

 

Best regards

Jorge

Edited by JorgeF
Link to post
Share on other sites

Hi

 

I don't see that as an issue.

For me it looks like an error in program organization.

 

When a "C" file is parsed it can not find two definitions for the same symbol.

A declaration with an "extern" defines the symbol just like the main definition. The only difference is that it doesn't allocate program/memory room for it because its is done in a different module.

If in the parser path it finds both the declaration and the definition its still a double definition for the same object so its an error.

The "extern" declaration can't never be placed in the same parser path, diirectly or included, as the definition of the same object.

 

Probably what you need is to review the organization of your ".h" files and their inclusion, including nested inclusion, in the various "C" modules.

 

 

 

Best regards

Jorge

 

The problem with this theory, and I just discovered this, is that if I change the function type from a function pointer to just a standard function, it compiles. So to illustrate:

 

This doesn't work:

BOOL( *functionname ) ( void );

 

extern BOOL( *functionname ) ( void );

 

 

This works:

BOOL functionname( void );

 

extern BOOL functionname( void );

Link to post
Share on other sites

Hi

 

 

I don't exactly know what the parser is suposed to do with the "extern" modifier applied to a function.

But I never used or see it being used to publish a function name.

I even made a quick browse of some reference sites in the net and couldn't find any mention to using "extern" in a function declaration.

AFAIK a function is published solely by its prototype.

Beeing so, this is my interpretation of your samples.

 

Sample 1 - Variable declaration

This doesn't work:

BOOL( *functionname ) ( void );

 

extern BOOL( *functionname ) ( void );

When the parser finds this two statements in the same "c" module (plus inclusions) it sees the

1 - The variable defined in this module

2 - The same variable declared as if it is defined in other module.

 

Sample 2 - Function declaration

This works:

BOOL functionname( void );

 

extern BOOL functionname( void );

When the parser finds this two statements in the same "C" module (plus inclusions) it sees the

1 - A function prototype. The function can be defined later in this same "C" module or in another one.

2 - The same function prototype but preceeded with "extern".

As the compiler doesn't throw errors nor warnings at this it looks like:

2.1 - The compiler is accepting multiple copies of the same function prototype. This might be a consequence of it supporting function overloading.

2.2 - It is ignoring the all statement, just because is a second declaration (not definition) of the same function or as a side efect of the, AFAIK, "odd" usage of the "extern" qualifier.

 

But, as I said its just my interpretation.

A more in depth analysis would require a detailed review of some of the "C" standards, to see if the compiler is behaving correctly or not.

 

Best regards

Jorge

Edited by JorgeF
Link to post
Share on other sites

Hi

 

 

I don't exactly know what the parser is suposed to do with the "extern" modifier applied to a function.

But I never used or see it being used to publish a function name.

I even made a quick browse of some reference sites in the net and couldn't find any mention to using "extern" in a function declaration.

AFAIK a function is published solely by its prototype.

Beeing so, this is my interpretation of your samples.

 

Sample 1 - Variable declaration

This doesn't work:

BOOL( *functionname ) ( void );

 

extern BOOL( *functionname ) ( void );

When the parser finds this two statements in the same "c" module (plus inclusions) it sees the

1 - The variable defined in this module

2 - The same variable declared as if it is defined in other module.

 

Sample 2 - Function declaration

This works:

BOOL functionname( void );

 

extern BOOL functionname( void );

When the parser finds this two statements in the same "C" module (plus inclusions) it sees the

1 - A function prototype. The function can be defined later in this same "C" module or in another one.

2 - The same function prototype but preceeded with "extern".

As the compiler doesn't throw errors nor warnings at this it looks like:

2.1 - The compiler is accepting multiple copies of the same function prototype. This might be a consequence of it supporting function overloading.

2.2 - It is ignoring the all statement, just because is a second declaration (not definition) of the same function or as a side efect of the, AFAIK, "odd" usage of the "extern" qualifier.

 

But, as I said its just my interpretation.

A more in depth analysis would require a detailed review of some of the "C" standards, to see if the compiler is behaving correctly or not.

 

Best regards

Jorge

 

For what it's worth, the code in question is the open source FreeModbus library, which compiled ok with HI-TECH, and is at v1.5 so it apparently has been around for awhile. It might be bad to assume this syntax is acceptable because of this, but that's my current thinking. Incidentally, I did see that a port of this same library is on the Sourceboost website, however ASCII mode was removed, leaving only RTU; therefore eliminating the need for these pointers.

 

I don't know alot about the internal workings of C compilers, but would be curious as to what the BoostC authors have to say.

Link to post
Share on other sites

I think what you have here is a bug. SB has a few issues with function pointers probably due to the memory architecture of the small PIC devices.

 

I think the storage class specifier 'extern' should always be used when refering to a function not in the current module.

Not using it is sloppy coding even if SB allows you not to use it.

Function overloading should not cause the problems here as each overload will have a different signature therefore the internally the function name will be different.

 

All the RAM bank switching does add a lot of overhead to your code which is why I am looking towards the Atmel AT devices with their Harvard architecture.

They also have real USARTS with parity for us oldies who are still using RS-232.

 

Cheers

 

Reynard

Link to post
Share on other sites

Hi

 

I think the storage class specifier 'extern' should always be used when refering to a function not in the current module.

Not using it is sloppy coding even if SB allows you not to use it.

 

It seems I've been reading and writing sloppy code for at least 30 years.

But is allways has been accepted by all compilers both "C" and "C++" on all platforms, since AT&T Unix were "C" was born, along "System V" from SCO, Hitec for ZX-Spectrum, Linux, DOS, Windows, PICs,......

And I've been reading much more than application code mine or from others, I also dig lots of standard header files on all kind of platforms and I can't recall seeing an "extern" modifier before a function prototype.

 

Anyhow, Hi-Tech is not exactly a reference for "C" coding, at least nor better or worse than BoostC.

You can browse the Microchip forum and found that not even XC8, the first generation from Hi-Tech after beeing bought by MCHP, is fully compatible with the previous Hi-Tech compilers.

After all "C" compilers for small micros like the PIC12/16/18 ranges must stretch standards a little bit due to the limitations of their targets.

 

 

And none of this alters the fact that any parser in the world would, or at least should, complain when it founds a double declaration along the same code path.

 

As for the double function prototype, I guess BoostC is silently ignoring it for the simple fact that function prototypes don't have any impact in code generation, they are only used to validate function calls.

Later the linker will have to deal with the actual calls, but as long as it find a function definitions that fits, everything is ok.

 

 

 

Best regards

Jorge

Edited by JorgeF
Link to post
Share on other sites

Hi Jorge,

 

Look inside the SB string.h file and it is full of the little extern blighters

 

The header files for the GCC compiler is full of them too.

 

The extern tells you that the function is not in this module but somewhere else. Maybe something to do with assisting the linker. Perhaps todays compilers silently ignore it.

 

Cheers

 

Reynard

Link to post
Share on other sites

Hi

 

Nop.

I think compilers simply accept it as optional when it comes to function prototypes, what makes some sense as they are really not needed for parsing or code generation. The semantichs of the "function prototype" simply made the "extern" redundant when applied to them.

On the other hand the "extern" is a must for variable declaration because of the storage allocation.

The only recommendation I found for using "extern" with a function prototype was in a document about "C#" (M$ personalized mix of C++ and Java) and the purpose was one of better documenting the code nothing else.

 

 

BTW

Take a look at "novo.h".

It looks like in the end its allways someone's personnal codding style.

 

 

Best regards

Jorge

Link to post
Share on other sites

Hi Jorge,

 

I suppose everyone has their own coding style.

 

I use extern when using GCC and Keil. I think it makes it clear the function resides elsewhere just like variables.

 

The compilers probably assumes extern unless told otherwise by seeing the full declaration.

 

Using extern for functions is probaly something that came over from assembler days (EXTERN).

 

I will keep writing my style of sloppy code.

 

Cheers

 

Reynard

Link to post
Share on other sites

Hi Reynard

 

How said anything about your code beeing sloppy?

 

Anyhow, it looks like the OP as stumbled on an "Hi-Tech C" issue of accepting a double declaration for a variable in the same parser path.

 

 

 

Best regards

Jorge

Link to post
Share on other sites

Hi Jorge,

 

You should read some of my code and you will see what sloppy is ;)

 

K & R 2nd edition says "the storage class for an externally-declared object may be left empty, or it may be specified as extern or static."

 

So it works either way.

 

Off topic:

Your Novo problem is a good one. I have it running on my EasyPIC5 board.

It says in the Novo source that the next task can be overridden by priority change or waiting task wakeup.

Maybe the last part has something to do with it (waiting task wakeup).

 

Cheers

 

Reynard

Link to post
Share on other sites

Hi

 

You should read some of my code and you will see what sloppy is ;)

You are not alone......neither are we..... :D

 

K & R 2nd edition says "the storage class for an externally-declared object may be left empty, or it may be specified as extern or static."

 

So it works either way.

Yeah, that makes the "extern" optional for function prototypes. But storage management makes it mandatory for variables.

As for "static", that is another ball-game.

 

This is consistent with my own experience on building parsers.

I already have 3 or 4 of them under my belt.............carefully stored in fat tissue. :D

 

 

Off topic:

Your Novo problem is a good one. I have it running on my EasyPIC5 board.

It says in the Novo source that the next task can be overridden by priority change or waiting task wakeup.

Maybe the last part has something to do with it (waiting task wakeup).

I will comment this one in the NOVO forum in its thread.

 

Best regards

Jorge

Edited by JorgeF
Link to post
Share on other sites

Function pointer is just another kind of a variable and should behave as other variables do. So if code like this:

 

extern int n;
int n;

 

compiles, similar code that uses function pointers should compile too:

 

extern void (*foo)(void);
void (*foo)(void);

 

This issue will be fixed in the coming release.

 

Regards,

Pavel

Link to post
Share on other sites

Hi Pavel

 

Now you got me all mixed up!

 

Is that code suposed to compile OK?

Declaring a a variable as being in defined in another module and them defining it in the current module?

 

 

Anyhow most of this thread was about the diffs in declaring and defining variables versus functions. It derived around post #4 from the OP and mine #5.

 

 

Best regards

Jorge

Edited by JorgeF
Link to post
Share on other sites

Hi

 

As I got a bit confused by Pavel, I decided to make my own testing with BoostC and ...

 

 

Yes the compiler behaviour is not consistent.

 

This code

extern void (*fun_ptr)(int *);
void (*fun_ptr)(int *);

issues a compiler error due to the redefinition of the symbol "fun_ptr".

 

And this code

extern int x;
int x;

Issues no compiler error, althought the redefinition of the "x" symbol is there.

 

But, after compiling comes linking and then the redefinition of "x" bites back because the linker is left with two "x" symbol to sort out, one from each module.

 

 

AFAIK

In this sample the "bug" is the compiler ignoring the redefinition of "x" not in complaining about the redefinition of "fun_ptr".

 

BTW: I'm not sure what the current "C" standards say about this.

 

But from a usage point of view, in such situation I would rather have a compile time error/warning pointing me to the source of the trouble, than to have to sort out the mess at linking time, as this means searching for the error somewere in the middle of 10?...20?....plus?..... source and header files of any half-decent project.

 

 

EDIT:

**Test code attached **

 

Best regards

Jorge

test_extern.zip

Edited by JorgeF
Link to post
Share on other sites

Function pointer is just another kind of a variable and should behave as other variables do. So if code like this:

 

extern int n;
int n;

 

compiles, similar code that uses function pointers should compile too:

 

extern void (*foo)(void);
void (*foo)(void);

 

This issue will be fixed in the coming release.

 

Regards,

Pavel

 

I'm really on a roll. This is possibly the 3rd compiler bug I've found in three different compilers in the last month or two. I say possibly because two are confirmed, including this one, and the 3rd one Microchip hasn't really admitted yet.

 

Anyway glad to see this will get resolved.

 

Pavel any idea on when the next release will be available?

Edited by jrmymllr
Link to post
Share on other sites

...Is that code suposed to compile OK?

Declaring a a variable as being in defined in another module and them defining it in the current module?...

 

Yes as you correctly noted in a following post it's the linker who will report an error if a variable is defined in more than one place. This might look a bit strange but the rationale for this kind of behaviour is that the code may be structured so that an 'extern' statement will be inside a header file that is included into all source files and one of these source files will have the actual variable definition:

 

common.h

extern int n;

 

source1.c

#include "common.h"
...

 

source2.c

#include "common.h"
...

 

source3.c

#include "common.h"
int n;
...

 

Pavel any idea on when the next release will be available?

 

We plan to have a new release within next 2 weeks (sometimes before Christmas)

 

Regards,

Pavel

Link to post
Share on other sites

Hi Pavel

 

 

I see your point, also see the advantage of that semanthics.

 

For some mysterious reason I never had that situation in almost 30 years of "C" and "C++" programming.

 

 

 

Best regards

Jorge

Link to post
Share on other sites

For some mysterious reason I never had that situation in almost 30 years of "C" and "C++" programming.

 

Me neither but I guess some do and compilers should allow this (i.e. gcc)

 

Regards,

Pavel

 

Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...