I have a beginner question in C. I'm having trouble in reading a file with values that initialize global variables to be shared in different C files. My true project has many variables to be used and changed across multiple files. My file that reads the parameters is:
#include <stdio.h>
#include <stdlib.h>
#include "parameters.h"
#include "prototypes.h"
#define MAX_LENGTH 100
int ReadParameters(void)
{
char line[MAX_LENGTH];
FILE *fp = fopen("parameters.in", "r");
if (! fp)
return EXIT_FAILURE;
int numread = 0;
while (fgets(line, MAX_LENGTH, fp)) {
numread += sscanf(line, "x = %d", &x);
numread += sscanf(line, "y = %d", &y);
numread += sscanf(line, "z = %d", &z);
}
fclose(fp);
return numread;
}
I defined the variables x, y, and z as external in a header file:
#ifndef PARAMETERS_H
#define PARAMETERS_H
extern int x;
extern int y;
extern int z;
#endif
The prototype of ReadParameters.c is in the header prototype.h and the values in x, y, and z are used in main.c:
#include <stdio.h>
#include <stdlib.h>
#include "parameters.h"
#include "prototypes.h"
int main()
{
ReadParameters();
printf("The value of x: %d\n", x);
printf("The value of y: %d\n", y);
printf("The value of z: %d\n", z);
x += 15;
y -= 5;
z -= 20;
printf("Now the value of x: %d\n", x);
printf("Now the value of y: %d\n", y);
printf("Now the value of z: %d\n", z);
return EXIT_SUCCESS;
}
When I compile I get the error of undefined reference to x, y, and z which I believe its because I only declared the variables not defined them. If I remove extern from the header file I get no errors and it runs but I read its not good practice to define variables in header files. If I make a another .C file and defined the variables there:
#include "parameters.h"
int x, y, z;
it works but is this ok to do? I'm new to programming and any suggestions would be appreciated. Thanks
extern means that the variables are available in some other compilation unit (ie. .c file). Typically you have one .h file for each .c file that "exposes" anything to other units.
So for something like this, I would probably have:
parameters.c
int x, y, z;
parameters.h
#ifndef PARAMETERS_H
#define PARAMETERS_H
extern int x;
extern int y;
extern int z;
#endif
main.c
#include "parameters.h"
int foo() {
x = 4; // setting x from parameters.c
}
extern tells the compiler that the definition of the variables lies else where( special case would be where variables are defined in the same compilation unit ). But linker should find these definitions. So, declare them extern in a header file(s) and include the header file in source files intended to use them. But don't forget to define them in exactly one source file. What you are doing seems ok to me.
it works but is this ok to do?
It is indeed regarded as bad practice, since it leads to "tight coupling" and spaghetti code.
The preferred way is this:
//parameters.h
void set_x (int x);
//parameters.c
#include "parameters.h"
static int private_x; // static means: only visible/accessible from parameters.c
void set_x (int x)
{
private_x = x;
}
// main.c
#include "parameters.h"
set_x (something);
Related
Can I have a function that gets defined differently due to value of some global variable -for example called "s"?
It should accept two integers if s equals 0, and one character otherwise.
I've tried using C preprocessor, but it seems that global variables cannot be accessed while preprocessing is being done.
# include <stdio.h>
int s = 1;
# if (s == 0)
void f(int x, int y);
# else
void f(char x);
#endif
int main(){
if (s == 0) f(0, 1);
else f('z');
return 0;
}
Surprisingly, in the above code f will be defined to accept two arguments, which logically is not expected.
I also do not want to change the main function.
You can do it in this way
# include <stdio.h>
#define S
# ifdef S
void f(int x, int y);
# else
void f(char x);
#endif
int main(){
# ifdef S
f(0, 1);
# else
f('z');
#endif
return 0;
}
And if you want to run the "else" version you just put the definition of S in a comment //#define S
I declared a struct on a header file, let's take this as example:
//file.h
#ifndef FILE_H_INCLUDED
#define FILE_H_INCLUDED
typedef struct {
int x;
int y;
} Point;
#endif // FILE_H_INCLUDED
Then I defined that struct on another file, that contains prototypes of function that I will use on main.c:
//functions.c
#include "file.h"
Point p = {{1},{2}};
Now my question is, how can I use that struct on main.c? Would like to do something like:
//main.c
#include "file.h"
printf("Point x: %d", p.x);
Now, my real struct got 8 fields and it's an array of 40 elements, so it's 40 rows of code, and I would like to not put it in main.c, as I want it as clear as possible. I can't use global vars tho.
Try this:
// file.h
typedef struct {
int x;
int y;
} Point;
void setup_point(Point *);
// functions.c
#include "file.h"
void setup_point(Point * p) {
p->x = 1;
p->y = 2;
}
// main.c
#include "file.h"
int main() {
Point p;
setup_point(&p);
printf("Point x: %d", p.x);
}
This is ideal as the logic for your struct is contained in a separate file and it does not use global variables.
Create a function the returns the address of p.
//file.h
Point *Point_p(void);
//functions.c
#include "file.h"
static Point p = {{1},{2}};
Point *Point_p(void) { return &p; }
//main.c
#include "file.h"
printf("Point x: %d", Point_p()->x);
I have a header file (generalfunctions.h):
#ifndef GENERALFUNCTIONS_H
#define GENERALFUNCTIONS_H
//functionsdeclartion for example
int getInt(char* text);
#endif /* GENERALFUNCTIONS_H */
and a C file generalfunctions.c where I include this headerfile (so I can use some of the functions within each other and don't have bother with their order) and code out the functions.
generalfunctions.c:
#include "generalfunctions.h"
#include <stdlib.h>
#include <stdio.h>
//functions implentaion for example
int getInt(char* text){
int i;
printf("%s\n", text);
if(scanf("%d", &i)==EOF){
printf("INT_ERROR\n");
exit(1);
}
while (fgetc(stdin) != '\n');
return i;
}
//...
Now I need some of these functions in a file called project_objects.c that together with project_objects.h defines a couple of structs, unions, variables and functions with these things I need for my project.
project_objects.h:
#ifndef POINT_H
#define POINT_H
typedef struct point{
int x;
int y;
} point;
point create_point(void);
void print_point(point *p);
//...
#endif /* POINT_H */
project_objects.c:
#include <stdlib.h>
#include <stdio.h>
#include "project_objects.h"
#include "generalfunctions.h"
point create_point(void){
point p;
p.x=getInt("Give my a x");
p.y=getInt("Give my a y");
return p;
}
void print_point(point *p){
printf("x: %d\n", p->x);
printf("y: %d\n", p->y);
}
//..
However I also need some of the functions described in generalfunctions.h directly in my main program:
#include "generalfunctions.c"
#include "project_objects.c"
#include <stdlib.h>
#include <stdio.h>
int main(void){
int i=getInt("How many points would you like to create?");
while(i<1){
i=getInt("Cannot create a negative number of points. How many points would you like to create?");
}
point pointarray[i];
for(int j=0; j<i; j++){
pointarray[j]=create_point();
}
for(int k=0; k<i; k++){
printf("Point %d:\n", k+1);
print_point(pointarray+k);
}
return EXIT_SUCCESS;
}
This seems to work. If I just include the h-files than I get the error that getInt() isn't defined when I link. And before when I included the C file for general functions in project_object.c I got errors for duplication. But now the files seem more dependent on each other than I planned. I also don't understand why this works.
Do not include .c-files. Write function protytypes in .h-files and include them.
project_object.h
typedef int faa;
foo.h
include "project_object.h"
faa foo( faa x ); // prototype for function "foo"
foo.c
#include "foo.h"
faa foo( faa x ) // implementation of function "foo"
{
return x + 666;
}
main.c
#include "project_object.h"
#include "foo.h" // include .h-file with prototype of function "foo"
int main( void )
{
faa x;
x = foo(0); // call function "foo"
return 0;
}
I've looked around for a good while if someone else has posted the same question and I haven't seen found an answer that applies to me.
Heres my problem:
When I pass 3 arguments (located in main) to another .c file, the information erases. If I keep the function inside main (not passing the arguments to another .c file) the program works just fine.
What am I missing here?
Also, I'm using a microcontroller, but I'm sure the problem is in my code.
main:
#include <avr/io.h>
#include <stdbool.h>
#include <stdio.h>
#include "glcd.h"
#include "fonts/Liberation_Sans15x21_Numbers.h"
//functions used:
void glcd_print_clock(void);
void time_clock(void);
void display_clock_text(uint8_t x, uint8_t y, uint8_t z);
int main(void)
{
glcd_init();
while(1)
{
time_clock();
}
}
//
void time_clock(void)
{
uint8_t sec, min, hr;
//char str_time[8] = "";
for(hr=1; hr<13; hr++)
{
for(min=0; min<60; min++)
{
for(sec=0; sec<60; sec++)
{
display_clock_text(hr,min,sec);
/*
//clears buffer
glcd_clear_buffer();
glcd_set_font(Liberation_Sans15x21_Numbers,15,21,46,57);
//sends hr, min, and sec to string
sprintf(str_time,"%02d:%02d:%02d",hr,min,sec);
//x-y coordinate of text
glcd_draw_string_xy(12,5,str_time);
//displays text
glcd_write();
_delay_ms(1000);
*/
}
}
}
}
Other .c file (display_text):
#include "glcd.h"
#include "fonts/Liberation_Sans15x21_Numbers.h"
#include <stdio.h>
#define Y_AXIS 5
#define X_AXIS 12
void display_clock_text(uint8_t x, uint8_t y, uint8_t z);
/* Gets the hour, minutes and seconds from main.
Then displays the information on the LCD
*/
void display_clock_text(uint8_t x, uint8_t y, uint8_t z)
{
char str_time[8] = "";
//clears buffer
glcd_clear_buffer();
//selects font to be used
glcd_set_font(Liberation_Sans15x21_Numbers,15,21,46,57);
//sends hr, min, and sec to string
sprintf(str_time,"%02d:%02d:%02d", x, y, z);
//x-y coordinate of text
glcd_draw_string_xy(X_AXIS,Y_AXIS,str_time);
//displays text
glcd_write();
_delay_ms(1000);
}
The line char str_time[8] = ""; is incorrect. It should be char str_time[9] = "";. This is because sprintf(str_time,"%02d:%02d:%02d", x, y, z); requires 9 bytes because of the terminating 0.
Also, a good idea, in general, would be:
snprintf(str_time, sizeof(str_time), "%02d:%02d:%02d", x, y, z);
This may or may not be causing the undesirable behavior that you are experiencing but it for sure needs to be fixed.
I'm a little confused about this:
#include <stdio.h>
#define MAXLINE 1000
int x;
int main()
{
int x;
getch();
return 0;
}
Where is the variable definition in this code? I'm assuming that it would be the external variable. In that case, shouldn't the variable in the function have an extern modifier?
What if the external variable was below the main function?
Example 1:
int x; // declares and defines global variable
int main()
{
int x; // declares and defines *new* local variable, which hides (shadows) the global variable **in this scope**
}
Example 2:
int main()
{
extern int x; // declares variable that will refer to variable defined *somewhere*
}
int x;
Example 3:
int x; // declares and defines global variable
int main()
{
extern int x; // redundant, declares variable that will refer to variable defined *somewhere*, but it is already visible in this scope
}
extern doesn't mean outside the current scope, it means an object with external linkage. An automatic variable never has external linkage, so your declaration int x inside main can't possibly refer to that. Hence it's hiding the global int x, that is, the the variable x with auto storage class is hiding the global x. You need to read more about storage classes in C
Refer the below program AFTER reading about them :
#include <stdio.h>
int i = 6;
int main()
{
int i = 4;
printf("%d\n", i); /* prints 4 */
{
extern int i; /* this i is now "current". */
printf("%d\n", i); /* prints 6 */
{
int *x = &i; /* Save the address of the "old" i,
* before making a new one. */
int i = 32; /* one more i. Becomes the "current" i.*/
printf("%d\n", i); /* prints 32 */
printf("%d\n", *x); /* prints 6 - "old" i through a pointer.*/
}
/* The "previous" i goes out of scope.
* That extern one is "current" again. */
printf("%d\n", i); /* prints 6 again */
}
/* That extern i goes out of scope.
* The only remaining i is now "current". */
printf("%d\n", i); /* prints 4 again */
return 0;
}