473,396 Members | 1,608 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Undeclared identifiers after program tidy-up?

I've started to split my code into modules, within the same Project folder in my compiler. I've done my best to sort this out, now I need an expert!

For example, in one of the .C files I have a function clsLCD(). This is defined and declared as a prototype in the associated .C file, plus declared as a prototype in my definitions.h file. However, when I build the project I get Undeclared identiifier 'clsLCD' in expression relating to another .C file that calls the function.

I've been told to repeat the definitions using extern, but do I have to repeat all the definitions in all the other modules, or can I have a single "defs.c" file with these extern definitions in it?

Could someone have a look at these files and explain how to get rid of these errors.

TIA

Nigel
Jan 15 '10 #1

✓ answered by Banfa

To start with functions should never, EVER be put into header files, its asking for trouble.

Also while having spaces in source file names is not strictly a problem it is also asking for trouble. I do not know any experienced programmer that would use a space in source a file name.

What you do is you do it in stages make sure each stage is working before starting the next stage.

Stage 1 - change nokia3310.h to nokia3310.c
  1. Rename nokia3310.h to nokia3310.c
  2. Move all declarations and definitions that might be used externally to nokia3310.c into a header file. Everything from line 8 - 44 of nokia3310.c is a candidate but the header file really does need to contain only the external interface, that is things that code external to nokia3310.c will need. I would call the new header file nokia3310.h, everything you need to include to use the functions in nokia3310.c.
  3. Next stop including the old nokia3310.h into Fuel Gauge.c and include the new header file (err which actually might be called nokia3310.h).
  4. Add nokia3310.c to your build, building the program consists of compiling Fuel Gauge.c, compiling nokia3310.c and then linking Fuel Gauge.obj, nokia3310.obj and any require libraries to produce the program. Where a .obj is the output produced from compiling a .c and might actually be a .o

Get this working first.

Stage 2 - Splitting up Fuel Gauge.c

Same as before really
  1. Move all declarations and definitions that might be used externally to Fuel Gauge.c into a header file. Everything from line 9 - 48 of Fuel Gauge.c is a candidate but the header file really does need to contain only the external interface, that is things that code external to Fuel Gauge.c will need. I would call the new header file Fuel Gauge.h, everything you need to include to use the functions in Fuel Gauge.c.
  2. Compile and link at this stage and get it working. This is true of all major structural changes, change 1 thing get it working before changing the next thing. You have a slight problem with the typedef of byte. Everything uses it but you do not really want to have to include all headers into all C files. I suggest putting the typedef of byte into its own header file, remembering to use include protections. Then all the other header files can included it. I often have headers (with no corresponding source files) in my projects that contain the typedefs of basic types I will use.
  3. Create a new C file and move the functions you wish to into it along with the same #includes as are already in Fuel Gauge.c.
  4. Add the new C file to your build similarly to the last stage of stage 1.

19 3326
johny10151981
1,059 1GB
I have asked a question several days ago about sharing a global variable in different c files.
including header file.

This can help you to understand extern

regards,
johny
Jan 15 '10 #2
Hi Johny,

I think I understand what extern means, but I'm still confused about how to resolve my problem.
Jan 15 '10 #3
Banfa
9,065 Expert Mod 8TB
You extern declarations should not be in any C/CPP source files. The should be in a H header file. You can then #include that header file into all your C/CPP file thus ensuring all the source files see the same set of declarations.
Jan 15 '10 #4
Hi Banfa,

So if I should change all the declarations in the definitions.h file to extern? I'm pretty sure I tried that, but I'll give it another go.
Jan 15 '10 #5
johny10151981
1,059 1GB
After you define variable in header file as extern then redefine the same variable with the same type without extern in c/c++ file. that will help... If I am not wrong

johny
Jan 15 '10 #6
Banfa
9,065 Expert Mod 8TB
You are both correct but nigelmercier you appear to have missed the rather important, critical you could say, step of

"#include that header file into all your C/CPP files"
Jan 15 '10 #7
Include the definitions header into all the files? Really?

[Later] Hey, it worked! I hadn't seen anywhere that I had to do this, thank you.

[Later still] Hmmm! When I first recompiled there was a single error, saying that the type 'byte' had been redefined, so I figured I could fix that. I now realize that this stopped the linker from running.

If I comment the typedef out in the main file, I get dozens of 'redefinition' errors saying something has already been defined in the main program - but it hasn't!

If I comment it out in the definitions.h file I get dozens of 'redefinition' errors, plus loads of other errors, such as '; expected but *** found' and 'Specifier needed'

[Even later still] If I add extern to all the declarations in the definitions.h file, then I get 'Unresolved extern ***'
Jan 15 '10 #8
weaknessforcats
9,208 Expert Mod 8TB
The essential thing to remember is that each .C file is compiled separately.

Therefore, all externs and struct declarations must be in that file. Should these externs and struct declarations be required in another .C file as well, then you need to have them there also.

In this case you can a) make a copy or b) use a #include file. Making a copy is not a good idea since any changes will need to be made in every.C file that's affected whereas a #include file requires the changes be made in one place only.
Jan 15 '10 #9
The essential thing to remember is that each .C file is compiled separately. Therefore, all externs and struct declarations must be in that file.

OK, that makes sense. But why am I still getting a whole bunch of errors?
Jan 15 '10 #10
johny10151981
1,059 1GB
in that case need to see the error messages
Jan 15 '10 #11
> in that case need to see the error messages

Too may to list, see my post above.
Jan 15 '10 #12
Banfa
9,065 Expert Mod 8TB
Hi Nigel,

a number of things could be going wrong.

Firstly I misled you slightly you do not want externs in front of everything, in particular you should not have externs in from of typedefs.

Secondly if you have more errors than you know what to do with then concentrate on the first one (sometimes the second and third ones provide clarification of the first one so it is worth reading them too). The reason for this is that after you have a single syntax error it is possible for the syntax parser to be unable to properly recover and start producing errors on code lines that would be perfectly valid if only that first error didn't exist. I mean this quite literally, a missing ; from the right (wrong?) place can literally produce hundreds of errors. Once you grow in experience you will learn when it is safe to try and fix the following errors but for now fix the first error an recompile is a not entirely unreasonable approach.

[Later still] Hmmm! When I first recompiled there was a single error, saying that the type 'byte' had been redefined, so I figured I could fix that. I now realize that this stopped the linker from running.

If I comment the typedef out in the main file, I get dozens of 'redefinition' errors saying something has already been defined in the main program - but it hasn't!
OK randomly commenting out lines of code is not a logical approach to programming, understand the error and fix it. Once you commented out a necessary typedef the fact you get lots of apparently in-explicable errors is not worth trying to explain, you are missing the definition of a required type. What you can do is learn from the mistake; observe the errors and remember the pattern for the next time you attempt to use a typedef'd type without actually having typedef'd the type (or included the correct header file).

So the actual error is that type 'byte' had been redefined (once you uncomment out the typedef). That is an easy error to explain the compiler has seen the typedef for byte more than once, the second+ time it sees the typedef it is a redefinition from the definition it already has and an error is produced.

How can this happen when it only appears once in definitions.h? Again easy to explain, you included the header definitions.h more than once into a single C/CPP file. All the the extern statements are not a problem since in effect all the do is say "hey did you know the symbol XXX exists?" to the compiler. The typedef is a problem because it actually creates something.

You have 2 solutions, the first, probably most obvious to a novice, is to make sure that you don't include your headers more than once into any given C/CPP file. However anyone with any experience will tell you that for any project of a reasonable size that allows headers to include other headers it is fairly impossible to ensure this which is why everyone uses the second approach of using include protection. Include protection is something you add to (all) you header files and it looks a little like this
Expand|Select|Wrap|Line Numbers
  1. #ifndef DEFINITIONS_H_
  2. #define DEFINITIONS_H_
  3.  
  4. // Body of header file here
  5.  
  6. #endif
  7.  
It uses the preprocessor (# directives are directives to the preprocessor rather than then compiler) to prevent the contents of the file being included more than once.

What happens is that the first time the header is included the symbol (DEFINITIONS_H_ in this case but it can be anything) is not defined so the body of header file is processed including defining the symbol. The second and subsequent times the file is included the symbol is already defined so the #ifndef directive causes the preprocessor to leave out the body of the file. So the file can be included multiple times but its statements will only be included once.

Every header file should use a different symbol name (for obvious reasons I hope) and it is convention to base the symbol name on an uppercased version of the actual header file name.
Jan 15 '10 #13
Hi Banfa,

Thank you for your detailed reply. First of all, could you clarify what a C/CPP file is. My compiler has .C and .H files, and keeps track of files in a project with a .MCPPI file (plus a bunch of .INI files that get rebuilt on every compile).

I only used the comment-out route because I knew there was a multiple typedef definition: one in the main .C file, and one in the .H file.

I take your point about a missing ; screwing up dozens of lines, but before I started to split the file it compiled fine.

I tried adding extern to the line in the .H file that gave the first error, and it fixed it. So I moved on to the next. After about 4 or 5 ties, I then did the rest. It could have been that the 'Unresolved extern ***' messages could have been there all the time, hiding at the bottom of a long list!
Jan 16 '10 #14
Banfa
9,065 Expert Mod 8TB
C/CPP file, 2 different types of file, C file if you are developing in C and CPP file if you are developing in C++.

Whenever you alter code layout, such as splitting 1 file into many, you run the risk of time spent ironing out introduced errors. The real trick is to avoid this sort of operation by developing in multiple files from the outset.

I only saw 1 typedef for byte in the code you posted and none of your files are called main.c

This is the first time you have mentioned "unresolved externals". That is a linker error not a compiler error. It is very important to identify which stage of the process is actually producing the errors.

Unresolved externals are symbols (functions or variables) that the linker can not resolve when it tries to create the executable. You would be extremely unlikely to get that error developing in a single file because the most likely cause is that you have your code spread across several C files but you are not linking all of the object files produce by compiling the C files.

The result is that the linker can not find the functions that are in the missing object file and it reports them functions as unresolved externals.

I think at this point it might be worth posting your code again if has change significantly from the original posting and posting the errors you are getting.
Jan 16 '10 #15
Hi Banfa,

Thank you again for your reply, this is my second attempt at a response, the server went down last time!

I plan to use multiple files in future, but this is my first large project.

I mentioned 'Unresolved extern' here, but that was after I did the mass add of extern to all the declarations in the definitions.h file. Seemed a good idea at the time :)

Would it be more use if I posted the original working code? If so, this file contains the original .C program, plus an include file nokia3310.h and two font*.h files (which are loaded by nokia3310.h).

What I want to do is:

Change the nokia3310.h file into a .C file, as it should be
Add a defs.h file with the declarations, global variables, prototypes etc
Split the existing .C file into multiple .C files at the sections marked:
// Tank Cal Functions
// Functions
void main()
Can you (or anyone else who is interested) suggest how best to do this?
Jan 16 '10 #16
Banfa
9,065 Expert Mod 8TB
To start with functions should never, EVER be put into header files, its asking for trouble.

Also while having spaces in source file names is not strictly a problem it is also asking for trouble. I do not know any experienced programmer that would use a space in source a file name.

What you do is you do it in stages make sure each stage is working before starting the next stage.

Stage 1 - change nokia3310.h to nokia3310.c
  1. Rename nokia3310.h to nokia3310.c
  2. Move all declarations and definitions that might be used externally to nokia3310.c into a header file. Everything from line 8 - 44 of nokia3310.c is a candidate but the header file really does need to contain only the external interface, that is things that code external to nokia3310.c will need. I would call the new header file nokia3310.h, everything you need to include to use the functions in nokia3310.c.
  3. Next stop including the old nokia3310.h into Fuel Gauge.c and include the new header file (err which actually might be called nokia3310.h).
  4. Add nokia3310.c to your build, building the program consists of compiling Fuel Gauge.c, compiling nokia3310.c and then linking Fuel Gauge.obj, nokia3310.obj and any require libraries to produce the program. Where a .obj is the output produced from compiling a .c and might actually be a .o

Get this working first.

Stage 2 - Splitting up Fuel Gauge.c

Same as before really
  1. Move all declarations and definitions that might be used externally to Fuel Gauge.c into a header file. Everything from line 9 - 48 of Fuel Gauge.c is a candidate but the header file really does need to contain only the external interface, that is things that code external to Fuel Gauge.c will need. I would call the new header file Fuel Gauge.h, everything you need to include to use the functions in Fuel Gauge.c.
  2. Compile and link at this stage and get it working. This is true of all major structural changes, change 1 thing get it working before changing the next thing. You have a slight problem with the typedef of byte. Everything uses it but you do not really want to have to include all headers into all C files. I suggest putting the typedef of byte into its own header file, remembering to use include protections. Then all the other header files can included it. I often have headers (with no corresponding source files) in my projects that contain the typedefs of basic types I will use.
  3. Create a new C file and move the functions you wish to into it along with the same #includes as are already in Fuel Gauge.c.
  4. Add the new C file to your build similarly to the last stage of stage 1.
Jan 16 '10 #17
Hi Banfa,

It's going well! I got as far as Stage 2.2, the typedef of byte.

In fuelg.h (renamed with no space as suggested) and nokia3310.h I have:

Expand|Select|Wrap|Line Numbers
  1. #include "typedefs.h"
The typedefs.h file is: [EDIT: this code is wrong, corrected later in [UPDATE #2]]

Expand|Select|Wrap|Line Numbers
  1. #ifndef byte
  2. typedef unsigned short int byte;
  3. #endif
Even so, I get "typedef name redefined: 'byte' - although this goes if I remove the include in fuelg.h

I plan to continue and ignore this for the moment ...



[UPDATE #1]

OK, I've create a new C file (cal.c) and added it to the project. I've moved the "// Tank Cal Functions" into it along with a copy of the same #includes as are already in Fuel Gauge.c - so the following appears in both Fuel Gauge.c and cal.c :

Expand|Select|Wrap|Line Numbers
  1. #include "nokia3310.h"
  2. #include <built_in.h>
  3. #include "fuelg.h" 
(The nokia3310.c file includes only its own .h file and the font .h files)

Now I get:

Redefinition of 'X [cal.c]'. 'X' already defined in 'Fuel Gauge.c'
where X is one of fuelRead8, gaugeStep, fuelCalTab, tabMax, txt4, txt7, i, or j

There are the items listed under //Global variables in fuelg.h

Expand|Select|Wrap|Line Numbers
  1. // Global variables
  2.  
  3. byte volatile fuelRead8; // fuel level from ADC made 8 bit
  4. byte volatile gaugeStep; // fuel step value, saved in EE StepStore
  5. byte fuelCalTab[BufSize]; // lookup table for fuel sensor calibration
  6. byte tabMax;              // index of last entry in table, saved in EE MaxStore
  7.  
  8. char txt4[4], txt7[7];    // temporary variables to hold conversion strings
  9. byte i, j;                // misc loops
I know globals are frowned upon, but almost every part of the program needs access to these. They ARE the program.

I'm guessing that I need include protection again, but as I couldn't get it to work last time I don't want to fiddle to much!



[UPDATE #2]

OK, I've seen that my #ifndef was wrong, so now fuelg.h and nokia3310.h have:

Expand|Select|Wrap|Line Numbers
  1. #ifndef fuelg_h
  2. #define fuelg_h
  3.  
  4. #endif
and

Expand|Select|Wrap|Line Numbers
  1. #ifndef nokia3310_h
  2. #define nokia3310_h
  3. // stuff
  4. #endif
and my typedefs.h file is:

Expand|Select|Wrap|Line Numbers
  1. #ifndef typedefs_h
  2. #define typedefs_h
  3. typedef unsigned short int byte;
  4. #endif
But I'm still getting Redefinition of 'X [cal.c]'. 'X' already defined in 'Fuel Gauge.c' with the globals as above.
Jan 17 '10 #18
Banfa
9,065 Expert Mod 8TB
Am I right in saying for all X each one equates to a variable name?

Taking fuelRead8 as an example the originally it was defined as

byte volatile fuelRead8; // fuel level from ADC made 8 bit


If you put that in a header file then it will be defined in every C file that the header is included into and you will get redefinition errors when you link. On the other hand if you put it into more than one C file so that they compiled it will be defined in every C file and you will get redefinition errors when you link.

For global variables you need to define it once for the linker and declare it everywhere for the compiler. You do this by putting

byte volatile fuelRead8; // fuel level from ADC made 8 bit

into 1 C file to define it and putting

extern byte volatile fuelRead8; // fuel level from ADC made 8 bit

into a header file to declare then it will be declared in every C file the header is included into but only defined in a single C file.


Having said that I will now say don't use global variables. They lead to errors because you have no control over who or what is changing the variable. It would be better to put this into a file

Expand|Select|Wrap|Line Numbers
  1. static byte volatile fuelRead8; // fuel level from ADC made 8 bit
  2.  
  3. byte getFuelRead8()
  4. {
  5.     return fuelRead8;
  6. }
  7.  
  8. void setFuelRead8(byte newValue)
  9. {
  10.     fuelRead8 = newValue;
  11. }
  12.  
This is slightly less efficient, variable access requires a function call but it does allow you to intercept all accesses to the variable if necessary and, for instance, you could range check the value before you allow it to be set.

This sometimes seems like overkill on a small micro-processor project like you are currently working on but is definitely worth doing on larger projects. Split the project into sub-modules and provide access to the module through functions rather than through direct access to the modules data.
Jan 17 '10 #19
>For global variables you need to define it once for the linker and declare it everywhere for the compiler.

BINGO! All working, thank you so much! I've kept the include protection in though, it seems worthwhile.

I take your point about using accessors for the global variables, and if this design goes public (as it may do soon) I will consider it.
Jan 17 '10 #20

Sign in to post your reply or Sign up for a free account.

Similar topics

3
by: Mike | last post by:
Greetings, I just used Tidy HTML for the first time. The address below contains the files need to check on Tidy's corrections. I would appreciate any feedback on the Tidy report and the...
12
by: Stefan Weiss | last post by:
Hi. (this is somewhat similar to yesterday's thread about empty links) I noticed that Tidy issues warnings whenever it encounters empty tags, and strips those tags if cleanup was requested....
40
by: VK | last post by:
Hi, After the response on my request from W3C I'm still unclear about Tidy vs. Validator discrepansies. That started with <IFRAME> issue, but there is more as I know. Anyway, this very basic...
0
by: BG Mahesh | last post by:
hi I have installed Tidy on Fedore Core 4.0 using RPM. I have a very simple script that uses tidy, ------------tidy.php------------------ <html>a html document</html> <? $html =...
1
by: Martin Odhelius | last post by:
Hello, Does anybody here have any example code for Tidy.Net (http://sourceforge.net/projects/tidynet/) ? I can't find one single example. I try to convert a html-string to well formed xhtml,...
10
by: teddarr | last post by:
I am trying to construct a class with several functions and identifiers. The identifier in question is static double AIR which will hold the value of the annual interest rate in the class. I have...
399
by: =?UTF-8?B?Ik1hcnRpbiB2LiBMw7Z3aXMi?= | last post by:
PEP 1 specifies that PEP authors need to collect feedback from the community. As the author of PEP 3131, I'd like to encourage comments to the PEP included below, either here (comp.lang.python), or...
5
by: vmagana | last post by:
First of all I would like to indicate that I am a newbie a programming. I am having a problem compiling a sample source code that I downloaded from microsoft. When I try to build the program I get...
2
by: BAnderton | last post by:
Greetings from beautiful Tucson, Arizona. Question: Is there a way in Python to determine what all file identifiers have been opened by Python, and to close them all? Why I ask: I learned...
0
by: kempshall | last post by:
Can somebody please tell me how to install the Tidy module for PHP 5 on a Mac? I tried what the php.net website said, which is running the command "pecl install tidy" but the installation failed...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.