Processor.c
#include<time.h>
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<string.h>
#include<stdlib.h>
#include<malloc.h>
#include<unistd.h>
#include"Process_struct.h"
sem_t empty;//semaphores
#define MAX_PROCS 5
#define EXIT 1
#define TRUE 1
char outbaseStr [100];
int numProcessors;
FILE *outLog=NULL;
FILE *file=NULL;
FILE *outFile=NULL;
FILE *temp=NULL;
pthread_t producer;//Producer Thread ID
pthread_t consumer[MAX_PROCS];//consumer thread ID
int main(int argc, char *argv[])
{
/* Initialize Data */
initializeData();
printf("argc equals %d\n", argc);
int num_processors=atoi(argv[2]);
int case_num=atoi(argv[3]);
char filename;
char *outfilename=argv[1];
printf("outfilename equals %s\n", outfilename);
printf("num_processors equals %d\n\n", num_processors);
switch(case_num)
{
case 1:
//printf("case 1\n");
/* Reading in from the text */
file = fopen("temp.txt", "wr");
/* fopen returns 0, the NULL pointer, on failure */
if(file==0||file==NULL)
{
printf("Error: couldn't open the file\n");
exit(EXIT);
}
/*****************************************************************************/
//write to temp
int length=argc-4;
for(int i=0;i<length;i++)
{
if(i%2==0)
{
//printf("%d ", atoi(argv[i+3]));
fprintf(file, "%d ", atoi(argv[i+4]));
}
else
{
//printf("%d\n", atoi(argv[i+3]));
fprintf(file,"%d\n", atoi(argv[i+4]));
}
}
/*****************************************************************************/
fclose(file);
file = fopen("temp.txt", "r");
/* Create the producer thread */
pthread_create(&producer, NULL, get_request, (void *)file);
break;
case 2:
//char filename[100];
//filename=argv[3];
//printf("usage: %s filename\n", argv[3]);
/* Reading in from the text */
file = fopen(argv[4], "r");
/* fopen returns 0, the NULL pointer, on failure */
if(file==0||file==NULL)
{
printf("Error: couldn't open the file\n");
exit(EXIT);
}
/* Create the producer thread */
pthread_create(&producer, NULL, get_request, (void *)file);
break;
default:
printf("Error: should be either case 1 or case 2\n");
exit(EXIT);
break;
}
pthread_join(producer, NULL);
//displayQ();
// Create the consumer threads
for(int i=0;i<num_processors;i++)
{
sprintf(outbaseStr, "%s.%ld", outfilename, (long)(i+1));
//printf("outbaseStr equals %s\n", outbaseStr);
outLog=fopen(outbaseStr, "w");
if(outLog==NULL)
{
printf("Error: couldn't open the file\n");
exit(EXIT);
}
pthread_create(&consumer[i], NULL, processor, (void *)outLog);
}
for(int i=0;i<num_processors;i++)
{
pthread_join(consumer[i], NULL);
}
//printf("\nfclose\n");
close((FILE *)file);
//fclose((FILE *)file);
if(case_num==1)
{
if(remove("temp.txt")!=0)
{
printf("error deleting file");
}
else
{
//printf("success deleting file");
}
}
}
Process_struct.c
#include<time.h>
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<string.h>
#include<stdlib.h>
#include<malloc.h>
#include<unistd.h>
#include"Process_struct.h"
sem_t empty;//semaphores
#define MAX_PROCS 5
#define EXIT 1
#define TRUE 1
char outbaseStr [100];
int numProcessors;
FILE *outLog=NULL;
FILE *file=NULL;
FILE *outFile=NULL;
FILE *temp=NULL;
pthread_t producer;//Producer Thread ID
pthread_t consumer[MAX_PROCS];//consumer thread ID
void initializeData()
{
//printf("initializeData\n");
//Create the empty semaphore and initialize it
sem_init(&empty, 0, MAX_PROCS);
// pthread_attr_init(attr);
}
void *get_request(void *argv)//this produces a queue
{
prcmd_t *process;
//printf("get_request\n");
if(file==NULL)
{
printf("\nwe have a file null error\n");
}
while(!feof(file))
{
process=(prcmd_t *)malloc(sizeof(prcmd_t));
fscanf(file, "%d %d", &process->owner, &process->burst_time);
if(process->owner!=0||process->burst_time!=0)
{
//printf("%d %d\n", process->owner, process->burst_time);
if(add_queue(process)==-1)
{
printf("failure from add_queue");
}
}
}
//printf("this is the end of get_request\n");
}
void *processor(void *argv)//this consumes a queue
{
prcmd_t *process;
// process=(prcmd_t *)malloc(sizeof(prcmd_t));
process=pr_head;
int sleep_time=process->burst_time;
//printf("\nprocessor\n");
while(TRUE)
{
if(get_number_request()>0)
{
if(remove_queue(&process)==0)
{
fprintf(outLog, "\n->Process with id %d and it %d de-equeue by thread \n", process->owner, process->burst_time);
clock_t start=clock();
sleep(process->burst_time);
clock_t end=clock();
fprintf(outLog, "\nSlept for %d seconds\n", sleep_time);
}
}
close((FILE *)outLog);
//fclose((FILE *)outLog);
//printf("the end of the processor\n");
//displayQ();
return NULL;
}
}
int get_number_request()
{
return pending_request;
}
void displayQ()
{
printf("\n\nthis is the beginning of displayQ\n");
prcmd_t *process=pr_head;
do
{
printf("%d %d\n", process->owner, process->burst_time);
process=process->next;
}while(process!=NULL);
printf("\nthe end of displayQ\n\n");
}
int add_queue(prcmd_t *node)
{
prcmd_t *temp;
temp=node;
pthread_mutex_lock(&prmutex);
//printf("add_queue\n");
//printf("%d %d\n", temp->owner, temp->burst_time);
/* adding a linkedlist to a queue */
if(pr_head==NULL)//then pr_tail==NULL
{
//printf("pr_head==NULL\n");
temp->next=NULL;
pr_head=temp;
pr_tail=temp;
}
else
{
//printf("pr_head!=NULL\n");
temp->next=NULL;
pr_tail->next=temp;
pr_tail=temp;
}
pending_request++;
pthread_mutex_unlock(&prmutex);
//printf("add_queue success\n");
return(0);
}
int remove_queue(prcmd_t **node)
{
//printf("\nremove_queue/enqueue\n");
pthread_mutex_lock(&prmutex);
prcmd_t *temp;
// printf("this is the end of remove_queue/enqueue and is returning 0\n");
if(pr_head==NULL)
{
//printf("pr_head==NULL");
pr_head = pr_tail = NULL; // Reset everything to empty queue
pthread_mutex_unlock(&prmutex);
//printf("this is the end of remove_queue/enqueue and is returning -1\n");
return(-1);
}
else
{
//printf("pr_head!=NULL\n");
temp=pr_head;
temp->next=pr_head->next;
pr_head=temp->next;
pending_request--;
pthread_mutex_unlock(&prmutex);
//printf("this is the end of remove_queue/enqueue and is returning 0\n");
return(0);
}
}
Process_struct.h
GNU nano 2.2.6 File: Process_struct.h
#include<time.h>
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<string.h>
#include<stdlib.h>
#include<malloc.h>
#include<unistd.h>
typedef struct pr_struct
{
int owner;
int burst_time;
struct pr_struct *next;
} prcmd_t;
void displayQ();//this displays the queue
void initializeData();//initializes the data for the program
void *get_request(void *args);//to be calls as a thread to enqueue input reques$
void *processor(void *args);//which removes a request from the process request $
int get_number_request();//returns the number of request
int add_queue(prcmd_t *);//adds a node at the end of the request queue
int remove_queue(prcmd_t **);//removes a node for the queue
#define MAX_PROCS 5
#define EXIT 1
#define TRUE 1
This is the error I have:
/tmp/ccvDJUQI.o:(.bss+0x0): multiple definition of `outLog'
/tmp/cc4RWdZ4.o:(.bss+0x0): first defined here
/tmp/ccvDJUQI.o:(.bss+0x8): multiple definition of `file'
/tmp/cc4RWdZ4.o:(.bss+0x8): first defined here
/tmp/ccvDJUQI.o:(.bss+0x10): multiple definition of `outFile'
/tmp/cc4RWdZ4.o:(.bss+0x10): first defined here
/tmp/ccvDJUQI.o:(.bss+0x18): multiple definition of `temp'
/tmp/cc4RWdZ4.o:(.bss+0x18): first defined here
collect2: error: ld returned 1 exit status
make: *** [Multiprocessor] Error 1
Whenever I go to run my make file this is the error I get. I don't understand where the error would be so I can't find it and change it. I was hoping someone could tell me what collect2: error: ld returned 1 exit status means and where the error would be at.
From your comment, it looks like you're trying to compile header files
gcc Processor.c Process_struct.h Process_struct.c -o Multiprocessor -std=c99 -lm -lpthread
A header file is included in a .c file and not compiled separately. Your command line should more look like
gcc Processor.c Process_struct.c -o Multiprocessor -std=c99 -lm -lpthread
Another source of this kind of errors, is when you define variables in a header file and include the header file in multiple source files, e.g. in Process_struct.h
FILE *file = NULL;
char temp[] = "/tmp";
When you include this header file in Processor.c and Process_struct.c, you define these variables in both sources and as a consequence get multiple defined variables.
To fix this, you must not define, but only declare the variables in the header file. You can then define them in one source file, e.g.
Process_struct.h:
extern FILE *file;
extern char temp[];
and in Process_struct.c:
FILE *file = NULL;
char temp[] = "/tmp";
Yet another source of multiple definitions is just that, you have defined the same variable in multiple places. This means when you have
Processor.c:
FILE *file = NULL;
char temp[] = "/tmp";
Process_struct.c:
FILE *file = NULL;
char temp[] = "/tmp";
you will get this error. The fix for this depends on your intention. If these variables are local to the file (independent from each other) narrow their scope to the file by prefixing with static
static FILE *file = NULL;
static char temp[] = "/tmp";
However, if you want to share the variables between these two sources, you must keep one definition and make the other one a declaration only. Better yet, move the declaration to a header file and keep the definition in only one source file, as in the second part above.
In any case, you should structure your makefile a bit differently. Use the built-in rules as much as possible, see Using Implicit Rules. E.g.
CFLAGS = -std=c99 -pthread
LDLIBS = -lm -lpthread
OBJS = Processor.o Process_struct.o
Multiprocessor: $(OBJS)
$(CC) $(CFLAGS) -o $# $(OBJS) $(LDLIBS)
For all user looking for an answer to collect2: error: ld returned 1 exit status, remember that it is helpful to make all the variables in your header file a STATIC variable. That's what made my error go away so to all other users that could be the answer to your error.
Related
I have 3 ".c" files called pre, sort and pipe. Pre takes a user input of names and GPA from a console. If the GPA is greater than or equal to 3.0, the name is stored into a struct.
Here's the pre.c file:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct student{
char temp_name[50];
char names[50];
};
int main()
{
int read_index = 0;
float check_gpa;
struct student data[read_index];
printf("Enter student name and GPA: \n");
scanf("%s %f\n", data[read_index].temp_name, &check_gpa);
read_index++;
while(scanf("%s %f\n", data[read_index].temp_name, &check_gpa) != EOF)
{
if (check_gpa >= 3.0)
{
strcpy(data[read_index].names, data[read_index].temp_name);
read_index++;
}
}
return 0;
}
The pipe file links the pre and sort files so that data from pre is sent to sort.
Here is the pipe.c file:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
char *args[] = {"./sort", NULL};
char *argv[] = {"./pre", NULL};
int pipe_end[2];
int pipe_id;
pipe(pipe_end);
if (pipe(pipe_end)==-1) // Check for pipe functionality
{
perror("Pipe Failed");
return 1;
}
pipe_id = fork();
if (pipe_id < 0) //Check for fork functionality
{
printf("Fork failed");
return 1;
}
else if(pipe_id == 0)//Child
{
close(pipe_end[0]);
dup(pipe_end[0]);
execvp(argv[0], argv);
}
else //Parent
{
wait(NULL);
close(pipe_end[1]);
dup2(pipe_end[1], 0);
close(pipe_end[0]);
execvp(args[0], args);
}
return 0;
}
The sort file takes names from a struct array and sorts them alphabetically and prints them to the console. And this is where the problem starts, because when I run the pipe file i get to enter names and GPA's But when ever I initiate an EOF (which is required and cannot change) by pressing Ctrl+D, I'm expecting the strings to be sent over to sort and displayed alphabetically, however this doesn't happen.
Here's the sort.c file:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
struct student{
char temp_name[50];
char names[50];
};
int main()
{
int print_index1 = 0,
print_index2,
read_index,
SIZE;
struct student data[print_index1];
SIZE = print_index1;
printf("Students with GPA's greater than or equal to 3.0, listed in alphabetical order:\n ");
for(print_index1 = 0; print_index1 < SIZE; print_index1++)
{
for(print_index2 = print_index1 + 1; print_index2 < SIZE; print_index2++)
{
if(strcmp(data[print_index1].names, data[print_index2].names) > 0)
{
strcpy(data[print_index1].temp_name, data[print_index2].names);
strcpy(data[print_index2].names, data[print_index1].names);
strcpy(data[print_index1].names, data[print_index1].temp_name);
}
}
printf("%s\n", data[print_index1].names);
}
return 0;
}
I've tested both files independently with user input and they worked. But a new problem has showed up, if you look at the sort file and notice I have a while loop that takes a for loop condition that I thought made sense> It worked a week ago but now it doesn't (unless it was a fluke). But that's my dilemma, I can't seem to get user input from "pre.c" over to "sort.c" I would really appreciate some help.
I also think the while loop in the "sort.c" file is causing an issue with printing the names.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Edit: I am really sorry if I have wasted time of your guys, I was running out of time when posting this problem. Here comes the code that I have done my best to minimize it
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum Error {
ERROR_UNRESOLVED_NAME = 1,
ERROR_CANNOT_OPEN_FILE,
ERROR_NO_ARGV,
ERROR_UNRECOGNIZED_SYMBOL,
ERROR_UNCOMPLETED_SENTENCE,
ERROR_RECURSIVE_SELF
};
struct _Piece;
typedef struct _Piece *(*PieceFunc)(struct _Piece *, void *);
struct _Piece {
PieceFunc function;
void *backpack;
};
typedef struct _Piece Piece;
Piece *piece_create(PieceFunc func, void *pack) {
Piece *piece = malloc(sizeof(Piece));
piece->function = func;
piece->backpack = pack;
return piece;
}
typedef struct _Record {
char *name;
int name_len;
Piece *piece;
struct _Record *previous;
} Record;
Record *record_register(Record *pre, char *name, int name_len, Piece *piece) {
Record *record = malloc(sizeof(Record));
record->name = name;
record->name_len = name_len;
record->piece = piece;
record->previous = pre;
return record;
}
typedef struct {
char *file_name;
char *source;
int length;
int current;
int line;
int column;
} Source;
Source *source_create(char *s, int len, char *file_name) {
Source *source = malloc(sizeof(Source));
source->source = s;
source->file_name = file_name;
source->length = len;
source->current = 0;
source->line = source->column = 1;
return source;
}
Piece *apply(Piece *caller, Piece *callee) {
return caller->function(callee, caller->backpack);
}
// Part 3, internals
Piece *internal_self(Piece *callee, void *backpack) {
if (callee->function == internal_self) {
fprintf(stderr,
"recursive `self` calling between two pieces\n"
"piece 1 backpack: %p\n"
"piece 2: %p backpack: %p",
backpack, callee, callee->backpack);
exit(ERROR_RECURSIVE_SELF);
}
return apply(callee, piece_create(internal_self, backpack));
}
Piece *internal_put(Piece *callee, void *backpack) {
int *p_char = callee->backpack;
putchar(*p_char);
return piece_create(internal_self, NULL);
}
Source *main_create_source(char *file_name) {
FILE *source_file = fopen(file_name, "r");
if (!source_file) {
fprintf(stderr, "cannot open file \"%s\"\n", file_name);
exit(ERROR_CANNOT_OPEN_FILE);
}
char *source = NULL;
int length = 0;
while (true) {
char *line = NULL;
int line_len = 0;
line_len = (int)getline(&line, (size_t *)&line_len, source_file);
if (line_len < 0) {
break;
}
if (source == NULL) {
source = line;
} else {
source = realloc(source, sizeof(char) * (length + line_len + 1));
strcat(source, line);
// free(line);
}
length += line_len;
}
fclose(source_file);
return source_create(source, length, file_name);
}
#define MAIN_REGISTER_INTERNAL(record, name, func) \
record = record_register(record, name, sizeof(name) - 1, \
piece_create(func, NULL)); \
printf("%p %p\n", record, record->previous);
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "please specify source file by command line argument\n");
exit(ERROR_NO_ARGV);
}
Record *r = NULL;
MAIN_REGISTER_INTERNAL(r, "put", internal_put);
printf("main %p\n", r);
Source *s = main_create_source(argv[1]);
printf("main %p\n", r);
}
At first, the program crashed with a segmentation fault, I located the bad access code line, which have been deleted in this code demo. I figure out the original bug is that variable r in main would unexpected change after an unrelated calling to main_create_source, which would be demonstrated like this (save this code file as foo.c)
$ cc -O0 -g foo.c
$ ./a.out futaba_test.ftb
0x7fc0024025b0 0x0
main 0x7fc0024025b0
main 0x7fc0024025b0
$ cc -O3 -g foo.c
$ ./a.out futaba_test.ftb
0x7fe861c025b0 0x0
main 0x7fe861c025b0
main 0x7fe800000000
The behavior varied when changing optimization level. It has nothing todo with EOF since I have removed it, and in my opinion the memory for strcat's destination is rich enough. Thanks for any help.
By the way if there is any requirement to point out the purpose of this snippet. This is an interpreter for a minimal language I am working on. It is able to evaluate small source code snippet at the time and this is the first time I have tried to build it with -O3. The bug will only disappear without any level optimization.
(The following is the original post and is able to be ignored.)
I have this code file. When compiling with cc -O0 futaba.c, and running it with ./a.out futaba_test.ftb, the result will be
0x7fba60c025b0 0x0
0x7fba60c025e0 0x7fba60c025b0
0x7fba60c02610 0x7fba60c025e0
0x7fba60c02640 0x7fba60c02610
0x7fba60c02670 0x7fba60c02640
0x7fba60c026b0 0x7fba60c02670
0x7fba60c026d0 0x7fba60c026b0
0x7fba60c02700 0x7fba60c026d0
0x7fba60c02730 0x7fba60c02700
main 0x7fba60c02730
main 0x7fba60c02730
A%
(Zsh add the postfix %) everything is going well. But when compiling with -O3 rather than -O0, than result will be
0x7f8f274025b0 0x0
0x7f8f274025e0 0x7f8f274025b0
0x7f8f27402610 0x7f8f274025e0
0x7f8f27402640 0x7f8f27402610
0x7f8f27402670 0x7f8f27402640
0x7f8f274026b0 0x7f8f27402670
0x7f8f274026d0 0x7f8f274026b0
0x7f8f27402700 0x7f8f274026d0
0x7f8f27402730 0x7f8f27402700
main 0x7f8f27402730
main 0x7f8f00000000
[1] 27811 segmentation fault ./a.out futaba_test.ftb
The last two main line print different address, and the second one is not valid, which cause the stack overflow bug later in record_resolve function.
What is the problem?
That's a lot of code, but here's at least a flag:
char source_fetch(Source *s) {
return s->current == s->length ? EOF : s->source[s->current];
}
This forces EOF into a char, which is a very bad idea. That's why all standard C functions that can return EOF (like getchar() return int.
No idea what an optimizing compiler can make out of that, but once you factor in code that waits for EOF using that ... it's smelly.
Note: this is perhaps bad form as an answer; but it's pointing out a concrete problem with the code.
Also none of the heap allocations seems to have code looking for NULL being returned; that's a bit scary too.
I am learning to write my own Virtual File system but besides the logical error in program something other than that keeps coming i checked all the declarations within the program but couldn't figure it out.
helper function
#include "header.h"
UFDT UFDTArr[50];
SUPERBLOCK SUPERBLOCKobj;
PINODE head=NULL;
void man(char *name)
{
if(name==NULL) return;
if(_stricmp(name,"ls")==0)
{
printf("Description : Used to list all information of file\n");
printf("Usage : ls\n");
}
else
{
printf("ERROR : No manual entry available\n");
}
}
void DisplayHelp()
{
printf("ls : To List Out all files \n");
printf("clear : To Clear consol\n");
}
void CreateDILB()
{
PINODE newn=NULL;
PINODE temp=head;
int i=1;
while(i<=MAXINODE)
{
newn=(PINODE)malloc(sizeof(INODE));
newn->LinkCount=newn->ReferenceCount=0;
newn->FileType=newn->FileSize=0;
newn->Buffer=NULL;
newn->next=NULL;
newn->InodeNumber=i;
if(temp==NULL)
{
head=newn;
temp=head;
}
else
{
temp->next=newn;
temp=temp->next;
}
i++;
}
}
void InitialiseSuperBlock()
{
int i=0;
while(i<50)
{
UFDTArr[i].ptrfiletable=NULL;
i++;
}
SUPERBLOCKobj.TotalInodes=MAXINODE;
SUPERBLOCKobj.FreeInode=MAXINODE;
}
void ls_file()
{
PINODE temp=head;
if(SUPERBLOCKobj.FreeInode== MAXINODE)
{
printf("Error : There are no files ");
return;
}
printf("\n File Name\tInode Number\tFile Size\tLink count\n");
printf("------------------------------------------------------------");
while(temp!=NULL)
{
if(temp->FileType!=0)
{
printf("%s\t\t%d\t\t%d\t\t%d\n");
}
temp=temp->next;
}
printf("------------------------------------------------------------");
}
main file
#include "header.h"
int main()
{
char *ptr=NULL;
int ret=0,fd=0,count=0;
char command[4][80],str[80],arr[1024];
InitialiseSuperBlock();
CreateDILB();
while(1)
{
fflush(stdin);
strcpy_s(str,"");
printf("Sachin VFS :> ");
fgets(str,80,stdin);
count=sscanf(str,"%s%s%s %s",command[0],command[1],command[2],command[3]);
if(count==1)
{
if(_stricmp(command[0],"ls")==0)
{
ls_file();
}
else if(_stricmp(command[0],"clear")==0)
{
system("cls");
continue;
}
else
{
printf("\n ERROR : Command not found!!! \n");
continue;
}
}
}
return 0;
}
header file
#define _CRT_SECURE_NO_WARNINGS
#define MAXINODE 50
#define READ 1
#define WRITE 2
#define MAXFILESIZE 1024
#define REGULAR 1
#define SPECIAL 2
#define START 0
#define CURRENT 1
#define END 2
#include<iostream>
#include <stdlib.h>
#include<string.h>
#include<io.h>
typedef struct superblock
{
int TotalInodes;
int FreeInode;
}SUPERBLOCK,*PSUPERBLOCK;
typedef struct inode
{
char FileName[50];
int InodeNumber;
int FileSize;
int FileActualSize;
int FileType;
char *Buffer;
int LinkCount;
int ReferenceCount;
int permission;
struct inode *next;
}INODE,*PINODE,**PPINODE;
typedef struct filetable
{
int readoffset;
int writeoffset;
int count;
int mode;
PINODE ptrinode;
}FILETABLE,*PFILETABLE;
typedef struct ufdt
{
PFILETABLE ptrfiletable;
}UFDT;
the one solution to this problem i got is declaring all the functions in main file above main to make compiler identify the functions but i still couldn't figure it out why it cant identify the same functions when i declare them in other file?
the default functions are working like system("cls"); but my functions are not working
could anyone help me to understand the reason of this error and possible solution ?
P.S.- I have pasted small part of my code the actual code is too long to post if anyone wants me to post it i will in comment section
In brief - you should declare ls_file() in your header.h:
void ls_file();
This is a common technique to export some objects / functions outside of file where they are defined. Both "implementation" and "client" *.c files must include that header. The former one - in order to guarantee consistency of actual definitions and publicly-visible declarations, the latter one - to provide client code with proper and explicit declarations.
... still couldn't figure it out why it cant identify the same
functions when i declare them in other file?
In general compiler should see declarations or definitions of functions / globals before any referencing to them. This is because during compilation process translator works only with one .c source, and knows nothing about another source files and their content.
P.S This answer may enlighten you a bit more.
I have written a small C program which is assembled of several files.
When I compile, I get an error for "multiple definitions".
My main.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"
#define FOREVER for(;;)
#define INPUT_LEN 30
int main()
{
char command[INPUT_LEN];
char *func;
int i;
int t;
FOREVER
{
if(scanf("%s", command) == 1)
{
func = strtok(command, " ");
for(i=0;cmd[i].func != NULL;i++)
{
if(strcmp(func, cmd[i].name) == 0)
{
(*((cmd[i].func)));
t = 1;
}
}
if(t == 1)
{
printf("No such command");
}
}
}
return 0;
}
My mat.c file:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"
#define LENGTH 100
#define SIXTEEN 16
#define SIZE 4
void read_mat()
{
int i = 0;
int j = 0;
int k = 0;
char tmp_name[LENGTH];
char num_buffer[LENGTH];
char *token;
double num_list[16];
double tmp_num = 0;
scanf("%[^,], %s", tmp_name, num_buffer);
token = strtok(num_buffer, ",");
while(token != NULL)
{
if(strcmp(token, "0") == 0)
{
num_list[i] = 0;
}
else
{
tmp_num = atof(token);
if(tmp_num == 0)
{
printf("Error in parameter: %d\n", (i-1));
break;
}
else
{
num_list[i] = tmp_num;
}
}
i++;
token = strtok(NULL, ",");
}
if(!strcmp(tmp_name, "MAT_A"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[0].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_B"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[1].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_C"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[2].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_D"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[3].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_E"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[4].mat[0][i][j] = num_list[k];
k++;
}
}
else if(!strcmp(tmp_name, "MAT_F"))
{
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
{
mats[5].mat[0][i][j] = num_list[k];
k++;
}
}
else
{
printf("No such matrix name.");
}
}
My general_structs.h file:
#define SIZE 4
#define SIZE_NAME 5
#define SIZE_FUNC 10
typedef double matrix[SIZE][SIZE];
matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;
void read_mat(void);
struct
{
char name[SIZE_NAME];
matrix *mat;
} mats[] = {
{"MAT_A", &MAT_A},
{"MAT_B", &MAT_B},
{"MAT_C", &MAT_C},
{"MAT_D", &MAT_D},
{"MAT_E", &MAT_E},
{"MAT_F", &MAT_F},
{"non", NULL}
};
struct
{
char name[SIZE_FUNC];
void (*func)(void);
} cmd[] = {
{"read_mat", read_mat},
{"not_valid", NULL}
};
My make file:
int_loop: my_math.o int_loop.o
gcc -g -ansi -Wall -pedantic my_math.o int_loop.o -o int_loop
int_loop.o : int_loop.c
gcc -c -ansi -Wall -pedantic int_loop.c -o int_loop.o
my_math.o : my_math.c
gcc -c -ansi -Wall -pedantic my_math.c -o my_math.o
I have been trying to solve this issue with various techniques but yet with no success.
The error I recieve is:
gcc -g -Wall -ansi -pedantic main.o mat.o -o mamantest
mat.o:(.data+0x0): multiple definition of `mats'
main.o:(.data+0x0): first defined here
mat.o:(.data+0x70): multiple definition of `cmd'
main.o:(.data+0x70): first defined here
collect2: ld returned 1 exit status
make: *** [mamantest] Error 1
Why does this error occurs? How do I solve this?
Thanks
In the header file you define the variables mats and cmd, meaning both translation units (both source files that includes the header file) will have those defined.
The variables should be defined only in a single place, in a single source file, like
struct mat mats[7] = { ... };
The above defines the array mats, and like I said should be done in only one place.
For the other source file you declare the variables, which can be done in the header file like e.g.
extern struct mat
{
...
} mats[7];
The above declare the variable mats as an array of seven mat structures. It also define the structure so it can be used to e.g. define the array.
After modifications suggested above, the complete header file should look something like
// First header include guards (see https://en.wikipedia.org/wiki/Include_guard)
#ifndef GENERIC_STRUCTS_H
#define GENERIC_STRUCTS_H
#define SIZE 4
#define SIZE_NAME 5
#define SIZE_FUNC 10
typedef double matrix[SIZE][SIZE];
// Declare the variables (note the added use of the extern keyword)
extern matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;
void read_mat(void);
// Define a structure named mat (note added structure tag name)
struct mat
{
char name[SIZE_NAME];
matrix *mat;
};
// Define a structure named command (note added structure tag name)
struct command
{
char name[SIZE_FUNC];
void (*func)(void);
};
// Now declare variables of the previous structures
extern struct mat mats[7];
extern struct command cmd[2];
// End of header include guard
#endif
That header file only declares variables, and can be included in all your source files.
Then in a single source file (for example your main.c file) you do the actual variable definitions:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "general_structs.h"
matrix MAT_A, MAT_B, MAT_C, MAT_D, MAT_E, MAT_F;
struct mat mats[7] = {
{"MAT_A", &MAT_A},
{"MAT_B", &MAT_B},
{"MAT_C", &MAT_C},
{"MAT_D", &MAT_D},
{"MAT_E", &MAT_E},
{"MAT_F", &MAT_F},
{"non", NULL}
};
struct command cmd[2] = {
{"read_mat", read_mat},
{"not_valid", NULL}
};
#define FOREVER for(;;)
#define INPUT_LEN 30
int main()
{
...
}
The important thing you need to learn here is that there is a difference between declaring and defining something.
A declaration is basically telling the compiler that "this thing exists somewhere", and a definition is telling the compiler "this is the thing".
The problem is that unless a thing has already been declared, a definition is also a declaration, and many simply call these combined definitions/declarations just declaration, which muddles the whole concept up a bit.
I will go ahead and say this is a homework assignment for an intro to Linux class. I would not be posting it without extensive attempts on my own, and seeing as I am a distance student this semester, I cannot make it to campus for tutoring. I need some help finding out what the issue is.
Essentially the assignment asks us to make a program that serves the same basic function as the pwd command in POSIX, to show the absolute path for the current directory. We are to use three functions along with main. We are not to use the getcwd command as well. I'll list them and their purpose
inum_to_filename: Accepts three arguments (inode number to translate, a pointer to a buffer where the name is written, and the size of the buffer). Returns nothing. It is to:
Open the current directory,
Read the first directory entry,
If the inode of the current directory matches the one passed in, copy name to buffer and return.
Otherwise read the next directory entry and repeat the previous step.
filename_to_inum: Accepts one argument (a char * representing the filename). It returns the corresponding inode number. It is to:
Read the information from the files inode into a structure in memory.
If there is any problem, display the appropriate error.
Return the inode number from the structure.
display_path: Accepts one argument (inode from the current working directory). It returns nothing. It is to:
Create an array of characters to use as a buffer for the name of the directory.
Get the inode for the parent directory using filename_to_inode.
If the parent inode is equal to the current inode, we have reached root and can return.
Otherwise, change to the parent directory and use inum_to_filename to find the name for the inode that was passed into the function. Use the buffer from step 1 to store it.
Recursively call display_path to display the absolute path.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
while (counter != 1) {
if (inode_arg == dirent_ptr->d_ino) {
strcat(pathBuffer, "/");
strcat(pathBuffer, dirent_ptr->d_name);
counter = counter + 1;
return;
} else {
dirent_ptr = readdir(dir_ptr);
}
}
closedir(dir_ptr);
}
int filename_to_inum (char *src) {
int res = 0;
struct stat info;
int result = stat(src, &info);
if (result != 0) {
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
} else {
res = info.st_ino;
}
return res;
}
void display_path (int ino_src) {
int bufSize = 4096;
char pathBuffer[bufSize];
int ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt) {
//print for test
inum_to_filename(ino_src, pathBuffer, bufSize);
printf("%s", pathBuffer);
return;
} else {
//print for test
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
}
int main (int argc, char *argv[]) {
int c_ino = filename_to_inum(".");
display_path(c_ino);
printf("\n");
}
As of right now it is displaying "/./MyName" with MyName being my personal named directory on the server. It is the directory I am running the program from. When using pwd I return "/home/MyName". I'm not really sure what my next step to getting the absolute path correct is.
The code is mostly set up to print one name at a time in the correct order, so the primary problem is the use of strcat() rather than strcpy(). Also, detecting when you're in the root directory at the start is important; if you don't, you can end up with /. or something similar (depending on exactly how you coordinate the printing) when the current directory is the root directory.
This version of your code has:
Squished the loop in inum_to_filename(), but also added error reporting. Remember, a process can be run in a directory which it does not have permission to get to (it requires a setuid program, usually — although permissions could be changed after the program is launched). In that case, it may fail to open .. (or .).
Lost variable count; it wasn't serving a useful purpose. Using the assign-and-test idiom allows the code to contain a single call to readdir().
Use strcpy() instead of strcat().
Use type ino_t to store inode numbers. Use size_t for sizes.
Reduce number of intermediate variables in filename_to_inum().
Note that the code in the if (ino_src == ino_prnt) statement body is for the root directory; in the absence of the testing print, it would do nothing.
Note that the printing in the else part is a major part of the operations, not just test printing.
Error check chdir("..");
Detect root in main().
Observe that this code is not directly suitable for rewriting into a function because it changes the process's current directory to / when it succeeds.
Revised code:
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
static void inum_to_filename(ino_t inode_arg, char *pathBuffer, size_t size_arg)
{
assert(size_arg > 0);
DIR *dir_ptr = opendir(".");
if (dir_ptr == 0)
{
fprintf(stderr, "Failed to open directory '.' (%d: %s)\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
struct dirent *dirent_ptr;
while ((dirent_ptr = readdir(dir_ptr)) != 0)
{
if (inode_arg == dirent_ptr->d_ino)
{
if (strlen(dirent_ptr->d_name) >= size_arg)
{
fprintf(stderr, "File name %s too long (%zu vs %zu max)\n",
dirent_ptr->d_name, strlen(dirent_ptr->d_name), size_arg);
exit(EXIT_FAILURE);
}
strcpy(pathBuffer, dirent_ptr->d_name);
break;
}
}
closedir(dir_ptr);
}
static ino_t filename_to_inum(char *src)
{
struct stat info;
if (stat(src, &info) != 0)
{
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
}
return info.st_ino;
}
static void display_path(ino_t ino_src)
{
size_t bufSize = 4096;
char pathBuffer[bufSize];
ino_t ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt)
{
// print for test
inum_to_filename(ino_src, pathBuffer, bufSize);
printf("%s", "(root): /\n");
}
else
{
// print for real
if (chdir("..") != 0)
{
fprintf(stderr, "Failed to chdir to .. (%d: %s)\n",
errno, strerror(errno));
}
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("/%s", pathBuffer);
}
}
int main(void)
{
ino_t c_ino = filename_to_inum(".");
ino_t r_ino = filename_to_inum("/");
if (r_ino == c_ino)
putchar('/');
else
display_path(c_ino);
printf("\n");
}
There are undoubtedly other ways to fix this.
Caveat: this is giving me some grief when working in /Volumes/CRUZER/Sub-Directory which is a memory stick. It fails to find the inode (1, which is surprising) when scanning /Volumes, and I've not worked out why. One of my programs — a getpwd implementation — is working fine; another is having a different problem. I expect I'll get to the bottom of it all. Testing on Mac OS X 10.10.5 with GCC 5.1.0.
this is really nice assignment :).
I read and tried your code, and it is almost correct. There were two small issues which were causing the incorrect behaviour.
First issue
When display_path reaches the root folder you don't need to call inum_to_filename and print the name of the folder because you have already printed the first folder of the path in the previous iteration. This prevents your code from showing a "./" in the beginning of the path.
That is, the if condition becomes:
if (ino_src == ino_prnt) {
return;
} else {
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
Second Issue:
You're not initializing propertly the buffer where you save the name of the directory. This causes random values to be displayed. To solve this issue you can just set the initial value of the buffer to zero by using memset.
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
memset(pathBuffer, 0, size_arg);
while (counter != 1) {
...
}
closedir(dir_ptr);
}
Full code working :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
memset(pathBuffer, 0, size_arg);
while (counter != 1) {
if (inode_arg == dirent_ptr->d_ino) {
strcat(pathBuffer, "/");
strcat(pathBuffer, dirent_ptr->d_name);
counter = counter + 1;
return;
} else {
dirent_ptr = readdir(dir_ptr);
}
}
closedir(dir_ptr);
}
int filename_to_inum (char *src) {
int res = 0;
struct stat info;
int result = stat(src, &info);
if (result != 0) {
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
} else {
res = info.st_ino;
}
return res;
}
/*
- Create an array of characters to use as a buffer for the name of the directory.
- Get the inode for the parent directory using filename_to_inode.
- If the parent inode is equal to the current inode, we have reached root and can return.
- Otherwise, change to the parent directory and use inum_to_filename to find the name for
the inode that was passed into the function. Use the buffer from step 1 to store it.
- Recursively call display_path to display the absolute path.
*/
void display_path (int ino_src) {
int bufSize = 4096;
char pathBuffer[bufSize];
int ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt) {
return;
} else {
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
}
int main (int argc, char *argv[]) {
int c_ino = filename_to_inum(".");
display_path(c_ino);
printf("\n");
}
Output :
ubuntu#ubuntu-VirtualBox:~/dev$ vi pwd.c
ubuntu#ubuntu-VirtualBox:~/dev$ gcc pwd.c
ubuntu#ubuntu-VirtualBox:~/dev$ ./a.out
/home/ubuntu/dev
ubuntu#ubuntu-VirtualBox:~/dev$ pwd
/home/ubuntu/dev
ubuntu#ubuntu-VirtualBox:~/dev$