This question already has answers here:
How do I use extern to share variables between source files?
(19 answers)
Closed 2 years ago.
I've been trying to program an atmega328p in Atmel Studio (it's fun), but when I tried to separate my keypad code into it's own c file, I got an error.
Error 'keypad' undeclared (first use in this function) invisible_alarm C:\Users\kenkr\Documents\Atmel Studio\7.0\invisible_alarm\invisible_alarm\main.c 39
keypad is defined in a separate file, and I've ruled a few things out:
I didn't forget the h file (Using a symbol defined in keypad.h works)
The compiler isn't ignoring keypad.c (Errors in keypad.c appear in the compile output)
I didn't forget to add the .c/.h file to the project (They appear in the solution explorer)
I suspect the build order is messed up, but I'm not sure where build order is set in Atmel Studio, but that's just a guess. I put a sample of my files below. The only errors are from main.c referencing keypad.c.
// main.c
#define F_CPU 16000000
#define NULL 0
#include <util/delay.h>
#include <avr/io.h>
#include "lcd.h"
#include "keypad.h"
void example() {
int header_example = KEY_1; // From keypad.h, no error
uint16_t c_example = keypad; // from keypad.c, error
}
// ...
// keypad.h
#ifndef _KEYPAD_H_
#define _KEYPAD_H_
#define KEY_1 0
#define KEY_4 1
// ...
#endif
// keypad.c
#include <avr/io.h>
#include <util/delay.h>
#include "keypad.h"
#define NULL 0
uint16_t keypad = 0x0000;
// ...
You need to declare the variable in the header file:
// keypad.h
#ifndef _KEYPAD_H_
#define _KEYPAD_H_
#include <stdint.h> // commonly needed for uint16_t
#define KEY_1 0
#define KEY_4 1
// ...
extern uint16_t keypad;
#endif
I have the following source named lcd.c.
#include <stdio.h>
#include "lcd.h"
void print_mode(void)
{
printf("%d\n",LCD_MODE);
}
The header lcd.h contains the definition for LCD_MODE as follows.
#ifndef LCD_H
#define LCD_H
#include "util.h"
#ifndef LCD_MODE
#define LCD_MODE LCD_MODE_8BIT
#endif
void print_mode(void);
#endif /* LCD_H */
The file util.h contains
#ifndef UTIL_H
#define UTIL_H
#define LCD_MODE_8BIT 1
#define LCD_MODE_4BIT 0
#endif /* UTIL_H */
lcd.c will be compiled separately as part of some library. I want to use it with an application main.c as follows.
#include "util.h"
#define LCD_MODE LCD_MODE_4BIT
#include "lcd.h"
int main(void)
{
print_mode();
return 0;
}
The desired outcome is to print 0 as per the definition of LCD_MODE_4BIT in main.c. However, 1 is printed because the header file sees that LCD_MODE is not defined during the preprocessing for lcd.c. How should I go about passing the LCD_MODE option to print_mode() through the main application?
if you cannot recompile lcd.c you cannot use a macro in another source file, because lcd.o already has the value hardcoded.
You could create a static variable (which defaults to LCD_MODE) that you can change using a setter:
#include <stdio.h>
#include "lcd.h"
static int the_mode = LCD_MODE;
void print_mode(void)
{
printf("%d\n",the_mode);
}
void set_mode(int new_mode)
{
the_mode = new_mode;
}
lcd.h should contain the prototype for the new configuration function BTW:
void set_mode(int new_mode);
then in your main, you can:
set_mode(LCD_MODE);
(or drop that LCD_MODE macro everywhere because it solves nothing and adds to the confusion)
I have a weird problem with my C-Code that I don't really understand.
I have two header files os_memory.h and os_mem_drivers.h.
os_memory.h
#ifndef OS_MEMORY_H_
#define OS_MEMORY_H_
#include "lcd.h"
#include "os_mem_drivers.h"
static const MemAddr gui_alloc_table_start = 0x1C8;
#endif /* OS_MEMORY_H_ */
os_mem_drivers.h
#ifndef OS_MEM_DRIVERS_H_
#define OS_MEM_DRIVERS_H_
#include "os_memory.h"
#include "defines.h"
#include "os_core.h"
typedef uint16_t MemAddr;
#endif
If I try to compile this code the compiler gives me the error unknown type name 'MemAddr'. I don't get it because I included the right header files in each .h file so there shouldn't be any error.
Is there anything that I'm missing here?
I'm using AtmelStudio 6.1 and the C language for this project.
You should move the definition for type MemAddr before including "os_memory.h":
os_mem_drivers.h:
#ifndef OS_MEM_DRIVERS_H_
#define OS_MEM_DRIVERS_H_
#include <stdint.h>
typedef uint16_t MemAddr;
#include "os_memory.h"
#include "defines.h"
#include "os_core.h"
#endif
But a more important problem is the circular inclusion of "os_memory.h" and "os_mem_drivers.h". Each one includes the other: include guards prevent recursive inclusion but make it difficult to understand what is really going on. You should try and fix this issue.
So I have a header file let's say "header.h" which is protected as follows:
#ifndef __HEADER1_H
#define __HEADER1_H
//type and function def
typedef struct
{
float r; //process noise
float k; //process gain
}state_t;
int get_state(state_t* state, float b);
#endif
Now I have two other headers which I defined as follows:
#ifdef __HEADER2_H
#include "header.h"
//function def
#endif
Second header:
#ifdef __HEADER3_H
//function
//the reason it is done this way is for cnditional compiling such that if the caller
//defines __HEADER3_H t this file won't be included.
#include "header.h"
#endif
Now as I suspected the compiler complained that types and functions defined in header.h were not detected in the source implementation of header2 and header3. So I included header.h in the source files as well. Now the linker is complaining functions that are defined in header.h are multiply defined.
My understanding was since the header.h is protected by ifndef it will only be included once so I don't see the problem.
here is the error that I am getting:
Symbol get_state multiply defined(by kalman.o and dsp.o)
Is there any chance that I am doing something unusally wrong?
#ifndef __HEADER1_H
#define __HEADER_H
The problem is your guard (__HEADER_H) is different from what you are checking for (__HEADER1_H). Make these both the same value.
The typical "guard" for a header file is:
myheader.h:
#ifndef _MYHEADER
#define _MYHEADER
<do stuff>
#endif
Optionally where myheader.h is included, you can do:
#ifndef _MYHEADER
#include "myheader.h"
#endif
This is optional and basically is only to improve compile performance.
So I'm still getting used to modular programming, and want to make sure I'm adhering to best practices. If I have the two module header files below, will the the headers #included by each file (for example "mpi.h") be included multiple times? Is there a proper way to account for this?
Also, my module headers typically look like these examples, so any other criticism/pointers would be helpful.
/* foo.h */
#ifndef FOO_H
#define FOO_H
#include <stdlib.h>
#include "mpi.h"
void foo();
#endif
and
/* bar.h */
#ifndef BAR_H
#define BAR_H
#include <stdlib.h>
#include "mpi.h"
void bar();
#endif
And use the sample program:
/* ExampleClient.c */
#include <stdlib.h>
#include <stdio.h>
#include "mpi.h"
#include "foo.h"
#include "bar.h"
void main(int argc, char *argv[]) {
foo();
MPI_Func();
bar();
exit(0)
}
What do you mean by 'include'? The preprocessor statement #include file copies the contents of file and replaces the statement with these contents. This happens no matter
If by 'include' you mean "the statements and symbols in these files will be parsed multiple times causing warnings and errors", then no, the include guards will prevent that.
If by 'include' you mean "some part of compiler will read some part of these files", then yes, they'll be included multiple times. The preprocessor will read the second inclusion of the file and replace it with a blank line because of the include guards, which incurs a tiny overhead (the file is already in memory). Modern compilers (GCC, not sure about others) will probably be optimized to avoid this, however, and note that the file has include guards on the first pass and simply discard future inclusions, removing the overhead - Don't worry about speed here, clarity and modularity are more important. Compilation is a time-consuming process, for sure, but #include is the least of your worries.
To better understand include guards, consider the following code sample:
#ifndef INCLUDE_GUARD
#define INCLUDE_GUARD
// Define to 1 in first block
#define GUARDED 1
#endif
#ifndef INCLUDE_GUARD
#define INCLUDE_GUARD
// Redefine to 2 in second block
#define GUARDED 2
#endif
After (the first pass of) preprocessing, what will GUARDED be defined to? The preprocessor statement #ifndef or its equivalent, #if !defined() will return false if their argument is indeed defined. Therefore, we can conclude that the second #ifndef will return false, so only the first definition of GUARDED will remain after the first pass of the preprocessor. Any instance of GUARDED remaining in the program will be replaced by 1 on the next pass.
In your example, you've got something slightly (but not much) more complicated. Expanding all the #include statements in ExampleClient.c will result in the following source: (Note: I indented it, but that's not normal style for headers and the preprocessor won't do it. I just wanted to make it more readable)
/* ExampleClient.c */
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include <stdio.h>
#ifndef STDLIB_H
#define STDLIB_H
#define NULL 0 //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
//#include "foo.h"
#ifndef FOO_H
#define FOO_H
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
void foo(void);
#endif
//#include "bar.h"
#ifndef BAR_H
#define BAR_H
//#include <stdlib.h>
#ifndef STDLIB_H
#define STDLIB_H
int abs (int number); //etc.
#endif
//#include "mpi.h"
#ifndef MPI_H
#define MPI_H
void MPI_Func(void);
#endif
void bar(void);
#endif
void main(int argc, char *argv[]) {
foo();
MPI_Func();
bar();
exit(0); // Added missing semicolon
}
Go through that code and note when various definitions are performed. The result is:
#define STDLIB_H
int abs (int number); //etc.
#define STDLIB_H
#define NULL 0 //etc.
#define MPI_H
void MPI_Func(void);
#define FOO_H
void foo(void);
#define BAR_H
void bar(void);
With respect to your request for other criticism/pointers, why are you #including stdlib.h and mpi.h in all your headers? I understand that this is a stripped down example, but in general, header files should only include files necessary for the declaration of their contents. If you use a function from stdlib or call MPI_func() in foo.c or bar.c, but the function declarations are simply void foo(void), you shouldn't include these files in the header function. For example, consider the following module:
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c:
#include <stdlib.h> // Defines type size_t
#include "mpi.h" // Declares function MPI_func()
#include "foo.h" // Include self so type definitions and function declarations
// in foo.h are available to all functions in foo.c
void foo(void);
size_t length;
char msg[] = "Message";
MPI_func(msg, length);
}
In this example, the implementation of foo() requires stuff from stdlib and mpi, but the definition does not. If foo() returned or required a size_t value (typedef'ed in stdlib), you'd need to #include stdlib in the .h file.
Mostly no, with a bit 'yes'. Your header files will be 'read' more than once but at second and later time the preprocessor will cut off all the contents. This implies that it won't waste your compiler's time and also #includes inside your #ifdef blocks will be done only once (per header file).
It's a good practice. Myself, I also add the following line before #ifdefs:
#pragma once
When supported by the particular compiler, it guarantees that the file will actually be read only once. I think it's a little bit more optimal that way.
So, to sum up:
header guards like you are using prevent compiler from interpreting the header contents more than once but possibly can cause the preprocessor to parse it more than once (which is not a big problem),
#pragma once causes the particular header file to be read only once.
When using both, #pragma once should be in effect if supported by compiler; if not, header guards will apply.
1) GOOD: you have an "include guard". "stdlib.h", "mpi.h" and "void foo()" are only seen by the compiler the first time you #include "foo.h"
/* foo.h */
#ifndef FOO_H
#define FOO_H
#include <stdlib.h>
#include "mpi.h"
void foo();
#endif
2) BAD: This will #include the entire contents of "foo.h" every time you use it:
/* foo.h */
#include <stdlib.h>
#include "mpi.h"
void foo();
3) By #include", I mean "once per compilation unit" (i.e. the same .c source file).
This mainly "protects" against a header (foo.h) calling another header ("bar.h) which might recursively call the first header.
Every different compilation unit that #includes foo.h will always get "stdlib.h", "mpi.h" and "void foo()". The point is that they'll be seen only once - not multiple times in the same compilation unit.
4) This is all "compile-time". It has nothing to do with libraries (which are "link time").
Yes, mpi.h will be included multiple times (as will stdlib.h); if mpi.h has include guards similar to foo.h and bar.h, then it won't be an issue.