How to use Internal Linkage Properly?

I

Immortal_Nephi

I always write global variables and global functions on all modules.
I find a way how to encapsulate global variable and global function.
I place static on Modify() function and it becomes internal linkage
in file scope -- Color.h & Color.c. How do I place static on global
variable Red? Should I place static in header -- Color.h or source
code -- Color.c?
main() function is not supposed to modify Red outside of file scope
-- Color.h & Color.c. Red and Modify() are hidden. Why can't C
Compiler fail to report saying Red should be static.
Global variable and global function in file scope are ideal to be
written into static library or dynamic linked library file so main()
can reuse them. Can you please make correction for me in my example
code below.

/* Color.h */

#ifndef COLOR_H
#define COLOR_H

static int Red = 10;
extern int Green;
extern int Blue;

void Print();
static void Modify();

#endif // COLOR_H

#include "Color.h"

/* Color.c */

int Green = 20;
int Blue = 30;

void Print()
{
Modify();
}

void Modify()
{
Red += 10;
}

/* main.c */
#include "Color.h"

int main(void)
{
Red += 50; /* main() should not access Red because Red is internal
linkage. How can C Compiler fails to compile? */

Green += 100;
Blue += 200;
Print();
Modify(); / C Compiler failed to compile --Correct */

return 0;
}


Nephi
 
B

Ben Bacarisse

I always write global variables and global functions on all modules.
I find a way how to encapsulate global variable and global function.
I place static on Modify() function and it becomes internal linkage
in file scope -- Color.h & Color.c. How do I place static on global
variable Red? Should I place static in header -- Color.h or source
code -- Color.c?

Protecting access to variables is not simple. Maybe the best way is
to hide them away altogether, but using static on a variable in an
included file is not a good idea (in fact it is plain wrong).
main() function is not supposed to modify Red outside of file scope
-- Color.h & Color.c. Red and Modify() are hidden. Why can't C
Compiler fail to report saying Red should be static.
Global variable and global function in file scope are ideal to be
written into static library or dynamic linked library file so main()
can reuse them. Can you please make correction for me in my example
code below.

I think the best way is to move the variables into the .c file that
provides all the access functions and make then static there. This
means you now need to provide a way to get at the values from
functions outside of this file. One way would be to wite access
function like int get_red(void); and so on. Another way would be to
provide pointers to const qualified versions of the colours (in the .h
file):

extern const int *red_val; /* and so on */

and in the file that defines them:

static int red = 10;
const int *red_val = &red;
 
G

GPS

I always write global variables and global functions on all modules.
I find a way how to encapsulate global variable and global function.
I place static on Modify() function and it becomes internal linkage
in file scope -- Color.h & Color.c. How do I place static on global
variable Red? Should I place static in header -- Color.h or source
code -- Color.c?
main() function is not supposed to modify Red outside of file scope
-- Color.h & Color.c. Red and Modify() are hidden. Why can't C
Compiler fail to report saying Red should be static.

The compiler does what you told it to do.

There is no need for a warning, because you might someday want this
behavior.
Global variable and global function in file scope are ideal to be
written into static library or dynamic linked library file so main()
can reuse them. Can you please make correction for me in my example
code below.

/* Color.h */

#ifndef COLOR_H
#define COLOR_H

static int Red = 10;
extern int Green;
extern int Blue;

void Print();
static void Modify();

#endif // COLOR_H

#include "Color.h"

/* Color.c */

int Green = 20;
int Blue = 30;

void Print()
{
Modify();
}

void Modify()
{
Red += 10;
}

/* main.c */
#include "Color.h"

int main(void)
{
Red += 50; /* main() should not access Red because Red is internal
linkage. How can C Compiler fails to compile? */

Green += 100;
Blue += 200;
Print();
Modify(); / C Compiler failed to compile --Correct */

return 0;
}


Nephi

This method seems better to me:


/* Color.h */
#ifndef COLOR_H
#define COLOR_H
#include <stdio.h>
int getRed(void);
int getGreen(void);
....
int setRed(void);
int setGreen(void);

void printColors(FILE *FP);
#endif
....


/* Color.c */
#include <stdio.h>

static int red, green, blue;

int getRed(void) {
return red;
}

int setRed(int r) {
red = r;
return red;
}

....

void printColors(FILE *fp) {
(void)fprintf(fp, "rgb %d %d %d\n", red, green, blue);
}

/* main.c */
#include <stdio.h>
#include <stdlib.h>
#include "Color.h"

int main() {
setRed(getRed() + 50);
setGreen(getGreen() + 100);

printColors(stdout);


return EXIT_SUCCESS;
}


Depending on what you're building it might be cleaner, and simpler to
pass around a struct rgb { int red, green, blue; }; and provide access
functions for that.

Have fun!

George
 
I

Immortal_Nephi

The compiler does what you told it to do.

There is no need for a warning, because you might someday want this
behavior.





















This method seems better to me:

/* Color.h */
#ifndef COLOR_H
#define COLOR_H
#include <stdio.h>
int getRed(void);
int getGreen(void);
...
int setRed(void);
int setGreen(void);

void printColors(FILE *FP);
#endif
...

/* Color.c */
#include <stdio.h>

static int red, green, blue;

int getRed(void) {
    return red;

}

int setRed(int r) {
    red = r;
    return red;

}

...

void printColors(FILE *fp) {
    (void)fprintf(fp, "rgb %d %d %d\n", red, green, blue);

}

/* main.c */
#include <stdio.h>
#include <stdlib.h>
#include "Color.h"

int main() {
   setRed(getRed() + 50);
   setGreen(getGreen() + 100);

   printColors(stdout);

   return EXIT_SUCCESS;

}

Depending on what you're building it might be cleaner, and simpler to
pass around a struct rgb { int red, green, blue; };  and provide access
functions for that.

Have fun!

George,

Thanks for your help. I am curious to ask. Why is it necessary to
put 5 or 10 or more variables into struct? Would it be helpful to
reduce too many parameters in the function?

For example...
void F(int a, int b, int c, int d, int e);

Too many.

Do...
void F(ABC *abc);

Correct?

Nephi
 
D

David Thompson

Others have already answered about what you should do, but to address
your specific question about what you DID try:

/* Color.h */

#ifndef COLOR_H
#define COLOR_H

static int Red = 10;
extern int Green;
extern int Blue;

void Print();
static void Modify();

#endif // COLOR_H

#include "Color.h"
You can't #include Color.h within Color.h (outside the guard); that
would recurse infinitely. I assume you meant to put this at the
beginning of Color.c, as you (correctly) showed in main.c.
/* Color.c */
<snipped contents>
Aside: naming a routine Print() when what it actually does is Modify()
is misleading and confusing. 'Hiding' implementation details of a
module so that callers don't know about them is a Good Thing in
general (although as with all generalizations there are occasional
exceptions); but making the 'public' interface confusing is Bad.
But I assume (hope?) that this is only an example.
/* main.c */
#include "Color.h"

int main(void)
{
Red += 50; /* main() should not access Red because Red is internal
linkage. How can C Compiler fails to compile? */
Remember that #include in C is textual (or to be pedantic, lexical),
not like the semantic 'module' facilities is some other languages.
If you #include a 'static' declaration into each source file (or
formally translation unit), it is equivalent to writing that same
declaration in each of them, and has the effect of creating a
_separate_ (internal-linkage) variable IN EACH. So this reference in
main() is accessing main.c's Red, while the reference in Modify() in
Color.c (which I snipped) is accessing Color.c's Red.

<snip rest>
- formerly david.thompson1 || achar(64) || worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top