Defining variable in header file causes multiple variable definition - c

I was doing some test coding for generating the pattern base on given pattern string and done as follows:
The header file is test.h:
#ifndef test_h
#define test_h
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<stdlib.h>
extern char uid []= "123456789561";
void generate_uid(FILE *,char *, char);
#endif
The .c file are as follows: test.c
#include"test.h"
extern int count;
void generate_uid(FILE *fp,char *uid_t, char ch)
{
int index = rand()%12;
int i,j;
strcpy(uid_t,uid);
if(ch == ' ')
{
for(j=3;j<10;j+=6)
{
uid_t[j] = ch;
}
}
// Replace numbers with special chars or alphabets(small/capital)
else
{
if(index < 6)
{
for(i=0;i<index;i++)
{
uid_t[i]=ch;
}
}
else
{
for(i=index;i<strlen(uid);i++)
{
uid_t[i]=ch;
}
}
}
count++;
fprintf(fp,"\"%s\", ",uid_t);
return;
}
main.c:
#include"test.h"
int count = 0;
int main()
{
FILE *fp_char,*fp_test;
char invalid_chars;
char *uid_t = (char *)malloc(sizeof(char)*14);
fp_char = fopen("invalidchars.txt","r");
fp_test = fopen("uid_test.txt","w");
if(fp_test == NULL || fp_char == NULL)
{
printf("cannot open file.\n");
return;
}
while((invalid_chars = fgetc(fp_char)) != EOF)
{
if(invalid_chars == '\n')
{
continue;
}
generate_uid(fp_test,uid_t, invalid_chars);
}
//Greater than 12 digit
strcpy(uid_t,uid);
strcat(uid_t,"2");
count++;
fprintf(fp_test,"\"%s\", ",uid_t);
//Less than 12 digit
strcpy(uid_t,uid);
uid_t[11]='\0';
count++;
fprintf(fp_test,"\"%s\", ",uid_t);
count++;
fprintf(fp_test,"\"%s\", ","NULL");
count++;
fprintf(fp_test,"\"%s\", ","empty");
free(uid_t);
fclose(fp_char);
fclose(fp_test);
printf("Number of string count : %d\n",count);
return 0;
}
Makefile is:
all : test.o main.o run
run : test.o main.o
$(CC) -g $^ -o $#
%.o : %.c
${CC} -g -c $< -o $#
.PHONY : clean
clean :
-rm -f *.o run
When I was compiling it gives the following:
cc -g -c test.c -o test.o
cc -g -c main.c -o main.o
cc -g test.o main.o -o run
main.o:(.data+0x0): multiple definition of `uid'
test.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [run] Error 1
Where I am going wrong.

You can declare a global variable in a header file, but not attribute it a value, because you can do it only once. So if you include your test.h file in more than one .c file (that would be usual), your compiler will see many initializations of the same thing when it will assemble your .o files.
Let only that in your test.h file :
extern char uid [];
And in one specific .c file (like uid.c for instance), initalize it :
char uid []= "123456789561";
Then add this new file to your Makefile.

You defined in header object
extern char uid []= "123456789561";
and this definition now is present in each compilation unit where the header is included. So the same object is defined several times and the compiler issues an error.
You should declare it in the header as for example
extern char uid [13];
and define it in one of the modules
char uid []= "123456789561";

Related

Undefined function reference in C

I've several files with main functions in C, for example, I've files called show.c, delete.c add.c (...). I also have a file, called interpreter.c, which may call one of the files, for example delete.c. Most of these file implement a main function, like the delete.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
int main (int argc, char *argv[])
{
int fd, rm;
char *caminho = argv[1]; // argumento inserido no terminal
char caminhod[30]="../TPSOFinal/";
strcat(caminhod,argv[1]);
fd = open(caminhod, O_RDONLY);
rm=unlink(caminhod);
// Verifica se o caminho inserido no input existe
if(rm == 0){
write(1,"Ficheiro eliminado!!!\n", 22);
return 0;
}
else{
write(1,"Erro ao eliminar ficheiro !!!\n", 29);
perror("Erro");
}
return 0;
close(fd);
}
The interpreter:
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <readline/readline.h>
#include <readline/history.h>
#define LER_BUFFER 1024
#define TBUFF 64
#define DELIM "\t\r\n\a"
int mostra(char **args);
int conta(char **args);
int acrescenta(char **args);
int apaga(char **args);
int informa(char **args);
int lista(char **args);
int manual(char **args);
int termina(char **args);
char *comando[] =
{
"mostra <caminho>",
"conta <caminho>",
"acrescenta <caminho> <caminho destino>",
"apaga <caminho>",
"informa <caminho>",
"lista <caminho>",
"manual",
"termina",
" ",
};
int (*fcomandos[]) (char**) =
{
&mostra,
&conta,
&acrescenta,
&apaga,
&informa,
&lista,
&manual,
&termina
};
int ncomandos()
{
return sizeof(comando)/sizeof(char*);
}
void processa(char *linha, char **argv)
{
while(*linha != '\0')
{
while(*linha == ' ' || *linha == '\t' || *linha == '\n')
{
*linha++ = '\0'; //troca caracteres especiais
}
*argv++ = linha; //guarda posição
while (*linha != '\0' && *linha != ' ' && *linha != '\t' && *linha != '\n')
{
linha++;
}
}
*argv = NULL;
}
char *lerlinha (void)
{
char *linha = NULL;
ssize_t tam = 0;
getline (&linha, &tam, stdin);
return linha;
}
char **separa (char *linha)
{
int tam = TBUFF, pos = 0;
char **palavras = malloc (tam *sizeof(char*));
char *palavra;
if (!palavras)
{
perror("Erro");
exit(EXIT_FAILURE);
}
palavra = strtok (linha, DELIM);
while (palavra != NULL)
{
palavras [pos] = palavra;
pos ++;
if (pos >= tam)
{
perror ("Erro");
}
}
palavra = strtok(NULL, DELIM);
palavras [pos] = NULL;
return palavras;
}
int launch (char **args)
{
pid_t pid, wpid;
int estado;
pid = fork();
if (pid == 0)
{
if(execvp(args[0],args)==-1){ perror ("Erro!"); }
exit (EXIT_FAILURE);
}
if (pid <0)
{
perror ("Erro!");
}
else
{
do{wpid = waitpid(pid, &estado, WUNTRACED);}
while (!WIFEXITED(estado)&& !WIFSIGNALED(estado));
}
return 1;
}
//Testa se os comandos existem
int mostra (char **args)
{
if (args[1] == NULL)
{
perror("sem argumentos ");
}
else if (chdir (args[1]) != 0)
{
perror ("Erro!");
}
return 1;
}
int conta ( char ** args)
{
if (args[1] == NULL)
{
perror("Sem argumentos ");
}
else if (chdir (args[1])!= 0)
{
perror ("Erro!");
}
return 1;
}
// Manual dos comandos
int manual (char **args)
{
int i;
printf("\n\nMiguel Oliveira\n");
printf("10260 - LESI\n");
printf("Sistemas Operativos e Sistemas Distribuidos\n");
printf("\nLista de Comandos\n");
for (i=0; i<ncomandos(); i++)
{
printf("%s\n", comando[i]);
}
return 1;
}
int termina (char **args)
{
return 0;
}
//Executa os comandos
int executar (char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i=0; i<ncomandos(); i++)
{
if (strcmp(args[0], comando[i])==0)
{
return (*fcomandos[i])(args);
}
}
return launch(args);
}
//Interpretador
void interpretador (void)
{
char *linha;
char **args;
int estado;
do
{
printf("%% ");
linha = lerlinha();
args = separa(linha);
estado = executar(args);
free(linha);
free(args);
} while (estado);
}
int main (void)
{
interpretador();
return EXIT_SUCCESS;
}
I've tried to research for similar problems, and i've found some little possible solutions, but cannot solve my problem, as show on bottom GCC compile mistake
You do not "call source files"; source files define functions and variables, and when compiled, ones defined in different files can use each other if they have a declaration (in a header file, usually) or a pointer (via dynamic link methods, like POSIX dlsym()).
Consider this minimal example. First, example.c:
#include <stdlib.h>
#include <stdio.h>
/* We expect someone else to define these */
extern int one(void);
int main(void)
{
printf("one() returned %d.\n", one());
return EXIT_SUCCESS;
}
and helper.c:
int one(void)
{
return 2; /* TODO: It's not one! */
}
You compile each source file to an object file:
gcc -Wall -O2 -c example.c
gcc -Wall -O2 -c helper.c
and then you link them to an executable program:
gcc -Wall -O2 example.o helper.o -o program
which you can run using
./program
Normally, each C source file that provides functions or variables usable outside that file, declares them in a header file. Here's a better example.
degrees.h
#ifndef DEGREES_H
#define DEGREES_H
double radians_to_degrees(double);
double degrees_to_radians(double);
#endif /* DEGREES_H */
The #ifndef, #define, and #endif are used as guards, so that if you #include the file more than once, the functions get declared only once. (The compiler will complain if it sees multiple declarations. Plus, we don't need to use extern here.)
The implementation of the above is then in degrees.c,
#ifndef PI
#define PI 3.14159265358979323846
#endif
double degrees_to_radians(double degrees)
{
return degrees * PI / 180.0;
}
double radians_to_degrees(double radians)
{
return radians * 180.0 / PI;
}
In a program myprog.c in the same project, you would use the above thus:
#include <stdlib.h>
#include <stdio.h>
#include "degrees.h"
int main(void)
{
printf("45 degrees is %.6f radians.\n", degrees_to_radians(45.0));
printf("2 radians is %.3f degrees.\n", radians_to_degrees(2.0));
return EXIT_SUCCESS;
}
and again you'd compile first the two source files to object files,
gcc -Wall -O2 -c degrees.c
gcc -Wall -O2 -c myprog.c
and then link together to a program, say myprog,
gcc -Wall -O2 degrees.o myprog.o -o myprog
which you can then run:
./myprog
It is also possible to compile and link the functions and variables declared in degrees.h to a static (libdegrees.a) or a dynamic (libdegrees.so) library, and install the header file to the standard location, so that your program could instead use #include <degrees.h> and the program link to the library via -ldegrees, but that is better left until you are well comfortable working with multiple files.
Until then, you might find the following Makefile useful
CC := gcc
CFLAGS := -Wall -O2
LDFLAGS :=
PROGS := myprog
all: clean $(PROGS)
clean:
rm -f *.o $(PROGS)
%.o: %.c
$(CC) $(CFLAGS) -c $^
myprog: degrees.o myprog.o
$(CC) $(CFLAGS) $^ -o $#
You can add multiple programs in the PROGS line, separated by spaces, and copy the myprog: lines for each, listing the object files that program needs.
With this, all you need to compile the program is to type make.
This forum eats Tabs, and Makefiles need indentation to use those. So, if you just copy-paste that to a file, it won't work. You can fix it, though, by running
sed -e 's|^ *|\t|' -i Makefile
which removes all initial spaces on each line with a tab in file Makefile.
If you use separate libraries, typically libm (#include <math.h>), you just need to add -lm (dash ell em) to the LDFLAGS line. If you eventually play with dynamic linking, that's -ldl.
If you were to write a graphical program using Gtk+, you'd append `pkg-config --cflags gtk+-3.0` (including the backticks `) to the CFLAGS line, and `pkg-config --libs gtk+-3.0` to the LDFLAGS line, and #include <gtk/gtk.h> to your program.

how to prevent the error multiple definition of main function in c?

I am getting the following error:
In function main:
electionTestsExample.c:(.text+0xf7): multiple definition of `main'
/tmp/cc5EeMIa.o:electionTestsExample.c:(.text+0xf7): first defined here
even though I only have one main function
here is my electionTestsExample.c:
#include <stdlib.h>
#include "elections.h"
#include "test_utilities.h"
/*The number of tests*/
#define NUMBER_TESTS 1
static bool deleteOnlyFirstArea (int area_id) {
return area_id == 1;
}
static bool testElectionRemoveAreas() {
Election election = electionCreate();
ASSERT_TEST(electionAddArea(election, 1, "first area") == ELECTION_SUCCESS);
ASSERT_TEST(electionAddArea(election, 2, "second area") == ELECTION_SUCCESS);
ASSERT_TEST(electionRemoveAreas(election, deleteOnlyFirstArea) == ELECTION_SUCCESS);
electionDestroy(election);
return true;
}
/*The functions for the tests should be added here*/
static bool (*tests[]) (void) = {
testElectionRemoveAreas
};
/*The names of the test functions should be added here*/
static const char* testNames[] = {
"testElectionRemoveAreas"
};
int main(int argc, char *argv[]) {
if (argc == 1) {
for (int test_idx = 0; test_idx < NUMBER_TESTS; test_idx++) {
RUN_TEST(tests[test_idx], testNames[test_idx]);
}
return 0;
}
if (argc != 2) {
fprintf(stdout, "Usage: election <test index>\n");
return 0;
}
int test_idx = strtol(argv[1], NULL, 10);
if (test_idx < 1 || test_idx > NUMBER_TESTS) {
fprintf(stderr, "Invalid test index %d\n", test_idx);
return 0;
}
RUN_TEST(tests[test_idx - 1], testNames[test_idx - 1]);
return 0;
}
here is my makefile:
CC=gcc
OBJS = electionTests.o election.o electionelem.o vote.o
EXEC = election
DEBUG_FLAG = -g
COMP_FLAG = -std=c99 -Wall -Werror
$(EXEC) : $(OBJS)
$(CC) $(DEBUG_FLAG) $(OBJS) -o $#
electionTests.o : electionTestsExample.c elections.h test_utilities.h
$(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) $*.c
election.o : elections.c elections.h election_element.h votes.h map.h
$(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) $*.c
electionelem.o : election_element.c election_element.h votes.h
$(CC) -c $(DEBUG_FLAG) $(COMP_FLAG) $*.c
vote.o : votes.c votes.h
You are looking at the code, but the answer lies in the build.
The error comes from the linker. It says main is defined twice, in the same file, at the same place. That suggests the file is being linked to itself.
For any function except main (which might not be a function), the linker ignores subsequent definitions; that's why you can override standard library functions like strcpy(3) or malloc(3). But there can only be one main, and two indicates a mistake.
My guess is you have both electionTestsExample.c and electionTestsExample.o on your command line.

Makefile returning error when incorporating other .c files

I've been working on an assignment where we are given a .ssv file that contains bank accounts in the first column and transactions in the second (20 is adding $20 and -20 is taking away $20), and are asked to create a linked list of the accounts using multiple c file.
There are three in question: main.c (opens the ssv and goes line by line), ssv.c (contains a function for parsing out the data from the fgets() string) and linked.c (creates the linked list and updates the account balances by matching the account number and adding the transaction). They are required to remain separate and cannot be made into .h files.
I've assembled a makefile to put all of them into one executable, but when I run the make, it returns and error. I did some debugging and found that it seems to compile objects files of ssv.c and main.c, but not linked.c, leading to some problems where I use linked.c functions in main.c. I've included each of the file's codes below, as well as the error message that appears when I try to "make". Any help finding the issue would be greatly appreciated.
Error Output:
ctonne2, ~/Projects/COMP206/Assignments/ass6: make
gcc -c linked.c
gcc -c ssv.c
gcc -c main.c
main.c: In function ‘main’:
main.c:21:3: warning: implicit declaration of function ‘parse’; did you mean ‘strsep’? [-Wimplicit-function-declaration]
parse(line,&acct, &amnt);
^~~~~
strsep
main.c:22:3: warning: implicit declaration of function ‘findUpdate’; did you mean ‘initstate’? [-Wimplicit-function-declaration]
findUpdate(acct, amnt);
^~~~~~~~~~
initstate
main.c:24:2: warning: implicit declaration of function ‘prettyPrint’ [-Wimplicit-function-declaration]
prettyPrint();
^~~~~~~~~~~
gcc -o linked.o ssv.o main.o
main.o: In function `main':
main.c:(.text+0x92): undefined reference to `findUpdate'
main.c:(.text+0xb6): undefined reference to `prettyPrint'
collect2: error: ld returned 1 exit status
makefile:2: recipe for target 'bank' failed
make: *** [bank] Error 1
ctonne2, ~/Projects/COMP206/Assignments/ass6:
makefile:
bank: linked.o ssv.o main.o
gcc -o linked.o ssv.o main.o
linked.o: linked.c
gcc -c linked.c
ssv.o: ssv.c
gcc -c ssv.c
main.o: main.c
gcc -c main.c
main.c:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
FILE* ssv = fopen("students.ssv", "rt");
if (ssv == NULL) {
printf("\n File opening failed");
exit(1);
}
int acct = 0;
float amnt = 0;
char line [100], bankAcc[10], balChange[10];
while (fgets(line, sizeof(line), ssv)) {
parse(line,&acct, &amnt);
findUpdate(acct, amnt);
}
prettyPrint();
}
linked.c:
#include <stdio.h>
#include <stdlib.h>
struct ACCOUNT {
int accountNumber;
float balance;
struct ACCOUNT* next;
};
struct ACCOUNT* head = NULL;
void findUpdate(int account, float amount) {
head = (struct ACCOUNT*)malloc(sizeof(struct ACCOUNT));
if (head == NULL) exit (1);
struct ACCOUNT* current = head;
int changed = 0;
while(current->next != NULL) {
if (current->accountNumber == account) {
current->balance = current->balance + amount;
changed++;
}
current = current->next;
}
if ((changed==0)&&(current->next==NULL)) {
struct ACCOUNT* newAccount=(struct ACCOUNT*)malloc(sizeof(struct ACCOUNT));
if (newAccount == NULL) exit(1);
current->next=newAccount;
newAccount->accountNumber = account;
newAccount->balance = amount;
newAccount->next = NULL;
}
}
void prettyPrint() {
struct ACCOUNT *current = head;
while (current!=NULL) {
printf("ACCOUNT ID: %4d BALANCE: $ %7.2f \n",current->accountNumber, current->balance);
current = current->next;
}
}
ssv.c
#include<stdio.h>
#include<stdlib.h>
void parse(char record[], int *acct, float *amnt) {
char *end;
char acctarr[10], amntarr[10];
sscanf (record, "%d %f", acct, amnt);
return;
}
Example .ssv file
10 100.0
20 -50.5
10 -20.0
You left out the output file in the rule for making the executable file.
bank: linked.o ssv.o main.o
gcc -o bank linked.o ssv.o main.o
Your command says to link just ssv.o and main.o, and put the result in linked.o.

Read through a text file and increment a variable every time an equals sign is encountered

I'm trying to write a program which will read through a makefile, and increment a counter every time an equals '=' sign is encountered in the file. Here is my attempt at such a program (the incrementation is not the sole purpose of this program, it just happens to be the point at which I am currently stuck):
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
struct VarMap {
int data;
int key;
};
// Use a hash table to store the variables - variablename : definition
void processFile(FILE* spData) {
int varCount = 0;
char buffer[1000];
while (fgets(buffer , sizeof(buffer) , spData) != NULL) {
if (buffer[0] == '#') continue;
for (int i = 0; i != '\0' ; i++) {
if (buffer[i] == '=') {
varCount++;
continue;
}
}
}
printf ("varCount has counted %d equals signs.\n\n" , varCount);
// This will hold the variables
struct VarMap variables[varCount];
}
int main(int argc, const char * argv[]) {
char filepath[1000];
printf("Enter the filepath of the Bakefile or bakefile: ");
scanf("%s" , filepath);
FILE* spData = fopen(filepath , "r");
if (spData == NULL) {
printf ("Cannot open file.");
exit(EXIT_FAILURE);
}
processFile(spData);
fclose(spData);
return 0;
}
The function we are interested in is the processFile function. My flow of reasoning was to read the file, line by line, into the array buffer, and then parse through the array until the first equals sign is found, at which I will increment varCount and continue to the next line. I can then use this variable to initialise a keymap to store the pairs of values corresponding to the variable names and their contents.
My issue is that the program, as written, is consistently returning 0 equals signs, whenever I run it and input the file with the following contents (obviously there exists equals signs but they are not being picked up):
calcmarks : calcmarks.o globals.o readmarks.o correlation.o
cc -std=c99 -Wall -pedantic -Werror -o calcmarks \
calcmarks.o globals.o readmarks.o correlation.o -lm
calcmarks.o : calcmarks.c calcmarks.h
cc -std=c99 -Wall -pedantic -Werror -c calcmarks.c
globals.o : globals.c calcmarks.h
cc -std=c99 -Wall -pedantic -Werror -c globals.c
readmarks.o : readmarks.c calcmarks.h
cc -std=c99 -Wall -pedantic -Werror -c readmarks.c
correlation.o : correlation.c calcmarks.h
cc -std=c99 -Wall -pedantic -Werror -c correlation.c
clean:
rm -f *.o calcmarks
As you may have guessed, I am trying to write an implementation in C for a program which can process a Makefile! Not an easy job, sadly.
So my question is;
What am I doing wrong / missing which is preventing varCount from being incremented?
The test condition for for loop should be:
buffer[i] != '\0'
Thanks to #achal for pointing it out.

Programming A PSP Application And Keep Getting A Linker Error (Undefined Reference)

I do not know why I keep getting this linker error because I linked the right library I am sure of it unless I am linking the wrong one but maybe someone knows which is the right library for the function SonyOskGu. The error is: main.c:(.text+0x134): undefined reference to `SonyOskGu(char*, unsigned int, char*, char*, int)'. The code is below:
#include <psposk.h>
#include "atoi.h"
PSP_MODULE_INFO("OSLib Sample", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
#define printf oslPrintf
#define ERROR_SUCCESS 0
#define ERROR -1;
int main(void)
{
oslInit(0);
oslInitGfx(OSL_PF_8888, 0);
oslInitConsole();
oslInitAudio();
printf("Press Any Key To Start OSK In Order To Enter Path Of Audio File To Play Audio:");
char* path = (char*)malloc(255);
SonyOskGu(path,0xff918f8c,0,0,100);
printf("The path is");
OSL_SOUND* sound = oslLoadSoundFile(path, OSL_FMT_NONE);
if (sound == NULL){
oslAssert(sound == NULL);
oslEndGfx();
oslQuit();
return ERROR;
}
else
{
printf("Press X To Play Or Press O To Stop!");
int key = oslWaitKey();
if (key == OSL_KEY_CROSS)
{
oslPlaySound(sound, 0);
}
else if (key == OSL_KEY_CIRCLE)
{
oslStopSound(sound);
}
}
oslEndGfx();
oslQuit();
return ERROR_SUCCESS;
}
The makefile is below:
TARGET = test
OBJS = main.o
INCDIR =
CFLAGS = -G4 -Wall -O2
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
LIBDIR =
LDFLAGS =
STDLIBS= -losl -lpng -lz \
-lpspsdk -lpspctrl -lpspumd -lpsprtc -lpsppower -lpspgu -lpspaudiolib -lpspaudio -lm -lpsposk -lpspgum -lpspgu -lpng -lz
LIBS=$(STDLIBS)$(YOURLIBS)
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = PSP Audio Player
PSP_EBOOT_ICON = ICON0.png
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak

Resources