From: Tim Roberts on
"Leslie Milburn" <CDB4W(a)NOSPAM.bigpond.com> wrote:
>
>"Tim Roberts" <timr(a)probo.com> wrote:
>
>> Although I agree that his current implementation has an almost unlimited
>> number of problems, the big issue he's facing is that he's writing for an
>> embedded processor. On many embedded processors, such as the PIC series
>> that he's targeting, the stack is your enemy. It can be very expensive to
>> use parameters and stack local variables, so you end up using globals more
>> than you ordinarily would.
>
>Then the static keyword is your friend as it is allocated the once and it
>can then be passed as a parameter as required. IMO this is much cleaner !!

I don't think you appreciate the problem. You've been working for too long
in systems with infinite memory and infinitely fast processors.

Parameters are part of the problem, as I said in my post. Sure, the code
is architecturally more "pure" by using parameters, but when your stack is
only 16 bytes long and it costs a dozen cycles to change stacks, you have
to make different choices.
--
Tim Roberts, timr(a)probo.com
Providenza & Boekelheide, Inc.
From: David Wilkinson on
Robby wrote:
> Hello Ron, one more thing,
>
> I have tried your suggestion but it compiles with an error. Here is the code:
>
>
> ===============KERNEL.h
> enum enumKM{KM_QUIT = 0, KM_CREATE = 1, KM_RECUR = 2};
> extern long MQ[10];
>
> ===============KERNEL.c
> #include <stdio.h>
> #include "KERNEL.h"
> #include "API.h"
>
> int main()
> {
> API_InsertMessage(KM_QUIT);
> return 0;
> }
> ===============API.h
> void API_InsertMessage(enum enumKM m);
>
> ===============API.c
> #include "API.h"
> #include "KERNEL.h"
>
> void API_InsertMessage(enum enumKM m)
> {
> long h=1;
> MQ[1]= h;
> }
> ==========================
>
> The following error is reported at compile time:
>
> 1>API.obj : error LNK2001: unresolved external symbol _MQ
>
> And I did include KERNEL.h in API.c as you indicated ?????

MQ[10] is declared but not defined.

If it is declared in KERNEL.h, it should be defined in KERNEL.c.

--
David Wilkinson
Visual C++ MVP
From: David Wilkinson on
Robby wrote:
> Ron,
>
> I don't think I would create a header file just dedicated to global externs.
> Becuase, then why not dedicate a header file for more than just extersn...
> why not just for externs and #defines and where do you draw the line as to
> what else we can put in there. So I would be mre comfortable with a KERNEL.h
> and put the exters, #defines and some struct declarations and include
> KERNEL.h in every .c file.
>
> So getting back to your suggestion, I guess that you meant it to be coded
> this way:
>
> ===============KERNEL.h
> enum enumKM{KM_QUIT = 0, KM_CREATE = 1, KM_RECUR = 2};
> extern long MQ[10];
>
> ===============KERNEL.c
> #include <stdio.h>
> #include "KERNEL.h"
> #include "API.h"
>
> long MQ[2] = {1,2];
>
> int main()
> {
> API_InsertMessage(KM_QUIT);
> return 0;
> }
> ===============API.h
> void API_InsertMessage(enum enumKM m);
>
> ===============API.c
> #include "API.h"
> #include "KERNEL.h"
>
> void API_InsertMessage(enum enumKM m)
> {
> long h=1;
> MQ[1]= h;
> }
> ==========================
>
> Now the above compiles without errors or warnings.

It does?

You have

extern long MQ[10]; // declaration

long MQ[2] = {1,2]; // definition

--
David Wilkinson
Visual C++ MVP
From: Ron Francis on
"Robby" <Robby(a)discussions.microsoft.com> wrote in message
news:C81EE069-E512-4220-A3BF-3CB6B2EFB239(a)microsoft.com...
> Ron,
>
> I don't think I would create a header file just dedicated to global externs.
> Becuase, then why not dedicate a header file for more than just extersn...
> why not just for externs and #defines and where do you draw the line as to
> what else we can put in there. So I would be mre comfortable with a KERNEL.h
> and put the exters, #defines and some struct declarations and include
> KERNEL.h in every .c file.
>
> So getting back to your suggestion, I guess that you meant it to be coded
> this way:
>
> ===============KERNEL.h
> enum enumKM{KM_QUIT = 0, KM_CREATE = 1, KM_RECUR = 2};
> extern long MQ[10];
>
> ===============KERNEL.c
> #include <stdio.h>
> #include "KERNEL.h"
> #include "API.h"
>
> long MQ[2] = {1,2];
>
> int main()
> {
> API_InsertMessage(KM_QUIT);
> return 0;
> }
> ===============API.h
> void API_InsertMessage(enum enumKM m);
>
> ===============API.c
> #include "API.h"
> #include "KERNEL.h"
>
> void API_InsertMessage(enum enumKM m)
> {
> long h=1;
> MQ[1]= h;
> }
> ==========================
>
> Now the above compiles without errors or warnings.
>
> Thanks all for your replies. Very appreciated

Robby,

Please excuse me being obvious, but I'm not sure how much you understand.
Yes, you still have to define MQ and it would make sense to do that in your KERNAL.c
When you use 'extern', you are just telling the compiler that the variable is defined elsewhere and
because the compiler couldn't find a definition anywhere, you got the error..

If you want to use MQ in another file, you have to tell it that it is defined somewhere else, so
normally you would normally put
extern long MQ [10];
near the beginning of the file.
Anyone reading the file can easily see that MQ is defined somewhere else.
If you 'hide' the declaration in KERNAL.h then someone would have to search for it.

You can think of a header file as just being an addition to a *.c file that it is embedded in.
That is, you can read it as all one file.

That is why David said ...
"You have
extern long MQ[10]; // declaration
long MQ[2] = {1,2]; // definition"
Because you have included KERNAL.h within KERNAL.c, it becomes one file and so you have made a
declaration and definition within the same file.
I'm surprised that it compiles but I don't know much about how compilers work.

Getting back to hiding the declaration, in my case, I put all my externs in their own header file
for readability.
Someone looking through a file wouldn't see an extern keyword, but I thought the next best thing
would be to see extern.h and hopefully assume that it would contain declarations.
If I had lots of #defines I would probably have a separate defines.h file, but I don't know that
this is common practice.
I think it is (or was) common to prefix a lowercase "g" to a variable to denote that it is global.
Something like g_MQ.

I know very little compared to many here, so I hope I haven't led you astray.
I'm sure I'll be corrected if I said something wrong.

Ron.

From: David Wilkinson on
David Wilkinson wrote:
> It does?
>
> You have
>
> extern long MQ[10]; // declaration
>
> long MQ[2] = {1,2]; // definition

Robby:

Actually, I now see that in the above (which I copied from your post), there is
an obvious typo in the definition, so the code most certainly will not compile.

I realize that your real code is too long to post, but there is a real danger in
just typing code into a post, because you will inevitably introduce errors that
are unrelated to the question you are asking.

The point under discussion could have been illustrated by the single file
complete program

extern long MQ[10]; // declaration

long MQ[2] = {1,2]; // definition

int main()
{
long n = MQ[0];
return 0;
}

If you had pasted this code into a test console project (as I did), you would
immediately have found two compiler errors.

After correcting the errors, you would find that if you commented out the
definition above (leaving only the declaration) then you would get a linker error.

Even if it does not help you to figure out the problem yourself, putting all the
code in a single file greatly increases the chance that a reader will paste your
code into a test project and figure it out for you. I always have such a test
project available for precisely this purpose.

--
David Wilkinson
Visual C++ MVP