Strange Compiler Behavior with Header Files

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone. First of all, I have to say that I have been able to make my code work. But it's not what I expect and I wanted to know if someone can help shed some light on the issue. Normally when I write a library, I put my definitions and function prototypes in a header file. Then my functions and whatever else in a .c file. The compiler kept giving me errors about the data type, which is strange because I've written other small libraries without any problems.

For example, my adc.c file would contain:

#include 
#include "adc.h"

// ***** Global Variables *****************************************************

// ***** Functions ************************************************************

void Setup_ADC(void)
{
    ADMUX |= (1<<REFS0);                // AVcc with external cap at AREF pin
    ADMUX |= (1<<ADLAR);                // left adjust result
    ADCSRA |= (1<<ADPS2)|(1<<ADPS1);    // 250 kHz (16MHz clock)
    ADCSRA |= (1<<ADEN);                // enable ADC
}

uint8_t readAnalog(uint8_t channel)
{
    ADMUX &= 0xF0;                  // clear lower four bits
    ADMUX |= channel;               // set channel
    ADCSRA |= (1<<ADSC);            // start conversion
    while(ADCSRA & (1<<ADSC)){}     // wait
    return ADCH;
}

And my adc.h file would have something like:

#ifndef ADC_H
#define ADC_H

// This line here has to be included, otherwise I get a compiler error, 
// eventhough it was already included once before. ???
#include 

// ***** Defintions ***********************************************************

// ***** Global Variables *****************************************************

// ***** Function Prototypes **************************************************

void Setup_ADC(void);
uint8_t readAnalog(uint8_t);

#endif

It seems like the compiler is complaining about the uint8_t data type in the readAnalog prototype not being defined. I've found that if I include avr/io.h everything's works great. But I shouldn't have to should I? Because the avr/io.h was already included in the adc.c file?

Without the extra include , the specific error message is:
adc.h:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'readAnalog'

Is this the normal way most people do things? I thought it was typical to put the include in the .c file. Or is the compiler just complaining for no reason and insisting that I include it twice?

Thanks in advance.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The *.h file is needed because one of the many other files it calls is for the defines of such data types. But when you include adc.h in adc.c, avr/io.h is NOT needed in the *.c ( as it's #include'd from adc.h ). IOW, it all works oppositely to the way you think it does.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

uint8_t is not a 'built-in' data type. The file happens to include 'inttypes.h', which defines uint8_t.

#include is required in adc.c , to provide definitions for the registers.

#include is required in adc.h , to provide the definition of 'uint8_t'.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Go to the tutorials forum and find "...Managing large projects", as it'll help you to understand how things go together.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To make adc.h completely "self standing" just add:

#include 

to the top of it. Any .h should include all necessary .h's that it is reliant on. The use of uint8_t in adc.h means it relies on stdint.h. Similarly if adc.h had used "PROGMEM" say then it would also need to include where that define is made.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
To make adc.h completely "self standing" just add:

#include 

to the top of it. Any .h should include all necessary .h's that it is reliant on. The use of uint8_t in adc.h means it relies on stdint.h. Similarly if adc.h had used "PROGMEM" say then it would also need to include where that define is made.

just for my understanding...
so including stdint.h in the header file would make including progmem.h and io.h in that header file nolonger needed? ( and then ofcoarse also not in the underlaying C files.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

just for my understanding...
so including stdint.h in the header file would make including progmem.h and io.h in that header file nolonger needed?

Err no. I was saying that adc.h uses something defined in stdint.h so to make adc.h standalome - a complete package if you like - you need to #include the thing it relies on.

The PROGMEM/pgmspace.h I quoted was simply a second example. I wasn't saying that adc.h is currently in any way dependent upon it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Normally when I write a library, I put my definitions
Explain what you mean by "definitions" since definitions should most certainly not be in header files.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Steve, I think he already has - by the example in the first post. So he does the right thing, but uses the wrong terms.

@meslomp:

These are declarations (only):

void foo(unsigned char c);
extern int i;

These are definitions (as well as declarations):

void foo(unsigned char c)
{
   PORTB = c;
}

int i;

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Steve, I think he already has - by the example in the first post.
He did not give an example of a variable declaration, only function prototypes.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mikericetga wrote:
#include is required in adc.c , to provide definitions for the registers.
Not if is #include'd in the *.h file. I don't get why OP wants just that 1 file, when the "master" *.h costs nothing to include and 1 doesn't hav eto go hunting for some specific *.h. Also, it would save some bytes to make a
static inline adc_init()

which can be put in the adc.h...and guess which file would be needed to make that happen ? :wink:

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are tradeoffs here.
The one OP made has the adc functions as external functions.
In that case, adc.h should #include stdint.h, not avr/io.h .
That way adc.h could be compiled for other platforms.
That might help with debugging or testing.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
Go to the tutorials forum and find "...Managing large projects", as it'll help you to understand how things go together.

Thanks for all the replies. I'll go check this out later. One of friends mentioned something about maybe using stdint, but neither he or I really knew anything about it at the time. This has been very helpful.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Quote:
Normally when I write a library, I put my definitions
Explain what you mean by "definitions" since definitions should most certainly not be in header files.

My terminology is probably not correct, since my degree program does not offer formal C classes. What I meant by definition is the actual #define statements. I usually put them in the header files.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

What I meant by definition is the actual #define statements.

In the C programming sense yhey aren't definitions or declarations in fact. A #define is a command to the preprocessor to define a macro but the C compiler itself never sees any of that as it's all replaced in the pre-processing stage before the C compiler ever gets to see the files. Same goes for #include's which is just another preprocessor command. The text of the files you #include (and then the files they #include and so on) are all simply inserted into one big file and that's what gets passed to the C compiler.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
What I meant by definition is the actual #define statements. I usually put them in the header files.
Which is fine, but you also had this:

// ***** Global Variables *****************************************************

These should be variable declarations, not definitions.

Regards,
Steve A.

The Board helps those that help themselves.