unsigned long int nextOffset, currOffset, len;
nextOffset = read offset from file (eg. 15)
currOffset = read prev offset from file (eg. 0 )
len = nextOffset-currOffset;
str = malloc((int)len);
fread(str,(int)(len)-1,1,dataFile);
str[(int)len]='\0';
rowAddr = ftell(tempDataFile);
fwrite(&rowAddr,sizeof(unsigned long int),1,tempOffsetFile);
fwrite(str,(int)(len)-1,1,tempDataFile);
free(str);
for some reason i'm not able to read from datafile using fread.. i debugged it and what i found was that the striing str is showing random data.. when i did this strlen(str) it shows 1709936.....
what is possibly wrong with this code.. all these files are opeend in binary mode...
What Ptival said.
But the most eggregious problem is that if you allocate n bytes, they are numbered from 0 to n-1. You're setting byte n to zero, and that byte is beyond the end of what you've malloc()ed. So you're probably unintentionally stomping on some other data. C won't keep you from shooting yourself in the foot this way.
Otherwise, based on what you said you needed, there doesn't seem to be much wrong with your code. I fleshed it out a bit, and wrapped it all in a little shell script for easy running. The script:
#!/bin/sh
# pgm 1 generates a binary file.
# pgm 2 dumps a file.
# pgm 3 demos a solution to your problem.
rm -f 1 2 3; \
cat > 1.c <<EOD; cat > 2.c <<EOD; cat > 3.c <<EOD; \
gcc -Wall -Werror 1.c -o 1; \
gcc -Wall -Werror 2.c -o 2; \
gcc -Wall -Werror 3.c -o 3; \
./1; ./2 dataFile.dat; ./3; \
./2 tempDataFile.dat; ./2 tempOffsetFile.dat
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char**argv)
{
unsigned int jndex;
unsigned char buffer[4];
FILE *phyle;
phyle=fopen("dataFile.dat","w+");
if(!phyle)
{
fprintf(stderr,"%s: fopen() fail\n",argv[0]);
exit(1);
}
for(jndex='A';
jndex<='Z';
jndex++
)
{
buffer[0]=jndex;
if(!fwrite(buffer,sizeof(char),1,phyle))
{
fprintf(stderr,"%s: fwrite() fail\n",argv[0]);
}
}
fclose(phyle);
printf("%s complete\n",argv[0]);
return 0;
}
EOD
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char**argv)
{
int jndex;
unsigned char buffer[4];
FILE *phyle;
if(argc!=2)
{
fprintf(stderr,"%s: arg error\n",argv[0]);
exit(1);
}
phyle=fopen(argv[1],"r");
if(!phyle)
{
fprintf(stderr,"%s: fopen fail\n",argv[0]);
exit(1);
}
for(jndex=0;
;
jndex++
)
{
if(!fread(buffer,sizeof(char),1,phyle))
{
break;
}
printf("%02X",buffer[0]);
if(jndex%16==15)
{
printf("\n");
}
else
if(jndex%2==1)
{
printf(" ");
}
}
if(jndex%16)
{
printf("\n");
}
fclose(phyle);
printf("%s %s complete\n",argv[0],argv[1]);
return 0;
}
EOD
#include <stdio.h>
#include <stdlib.h>
FILE *dataPhyle;
FILE *tempDataPhyle;
FILE *tempOffsetPhyle;
void do_one_guy(char *pgmName,
unsigned long int nextOffset,
unsigned long int curOffset
)
{
unsigned long int len;
long rowAddr;
char *str;
len=nextOffset-curOffset;
str=malloc(len);
if(str==NULL)
{
fprintf(stderr,"%s: malloc() fail\n",pgmName);
exit(1);
}
if(fread(str,sizeof(char),len-1,dataPhyle)!=len-1)
{
fprintf(stderr,"%s: fread() fail\n",pgmName);
}
str[len-1]='\0';
printf("record content is %s\n",str);
rowAddr=ftell(tempDataPhyle);
if(fwrite(&rowAddr,1,sizeof(rowAddr),tempOffsetPhyle)!=sizeof(rowAddr))
{
fprintf(stderr,"%s: fwrite(first) fail\n",pgmName);
}
if(fwrite(str,sizeof(char),len-1,tempDataPhyle)!=len-1)
{
fprintf(stderr,"%s: fwrite(second) fail\n",pgmName);
}
free(str);
}
int
main(int argc, char**argv)
{
dataPhyle=fopen("dataFile.dat","r");
if(!dataPhyle)
{
fprintf(stderr,"%s: fopen(\"dataFile.dat\") fail\n",argv[0]);
exit(1);
}
tempOffsetPhyle=fopen("tempOffsetFile.dat","w+");
if(!tempOffsetPhyle)
{
fprintf(stderr,"%s: fopen(\"tempOffsetFile.dat\") fail\n",argv[0]);
exit(1);
}
tempDataPhyle=fopen("tempDataFile.dat","w+");
if(!tempDataPhyle)
{
fprintf(stderr,"%s: fopen(\"tempDataFile.dat\") fail\n",argv[0]);
exit(1);
}
do_one_guy(argv[0],32,16);
do_one_guy(argv[0],12,8);
printf("%s complete\n",argv[0]);
return 0;
}
EOD
The output:
./1 complete
4142 4344 4546 4748 494A 4B4C 4D4E 4F50
5152 5354 5556 5758 595A
./2 dataFile.dat complete
record content is ABCDEFGHIJKLMNO
record content is PQR
./3 complete
4142 4344 4546 4748 494A 4B4C 4D4E 4F50
5152
./2 tempDataFile.dat complete
0000 0000 0F00 0000
./2 tempOffsetFile.dat complete
Hope this helps.
Related
I have a 3rd party C static library that uses xdr_wrapstring. I am moving to RH 8 where these symbols are not unavailable in the default /lib64/libc.so.6, but are available as versioned symbols (xdr_wrapstring#GLIBC_2.2.5)? Is there a way to tell the linker to resolve xdr_wrapstring to xdr_wrapstring#GLIBC_2.2.5?
I can't link with libtirpc (which provides unversioned symbols) due to it requiring libssl.so & libcrypto.so via libk5crypto.so
Prefaced by the top comments ...
The assembler .symver shows some promise. A web search on it shows:
http://web.mit.edu/rhel-doc/3/rhel-as-en-3/symver.html
https://man7.org/conf/lca2006/shared_libraries/slide19a.html
Linking against older symbol version in a .so file
From this, I've created a symver.s file that has stubs that seems to work on my system [which has the same versioned symbols issue].
However, I'd have a look at those linked pages (e.g.) symver is also an attribute, so it may be possible to do this with inline asm from a .c file.
I've created a crude test program:
// xdrtest.c -- print address of xdr_wrapstring
#include <stdio.h>
void xdr_wrapstring(void);
int
main(void)
{
void *ptr = xdr_wrapstring;
printf("%p\n",ptr);
return 0;
}
Here is an better test program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#define ALEN 1000
#define sysfault(_fmt...) \
do { \
fprintf(stderr,_fmt); \
exit(1); \
} while (0)
XDR xdrs;
void
sendstring(const char *str)
{
static char buf[ALEN];
char *bp;
strcpy(buf,str);
bp = buf;
if (! xdr_wrapstring(&xdrs,&bp))
sysfault("sendstring: xdr_wrapstring fail -- str='%s' buf='%s'\n",
str,buf);
}
void
recvstring(const char *str)
{
static char buf[ALEN];
char *bp;
bp = buf;
if (! xdr_wrapstring(&xdrs,&bp))
sysfault("recvstring: xdr_wrapstring fail -- str='%s' buf='%s'\n",
str,buf);
fprintf(stderr,"buf=%p bp=%p str='%s' bp='%s'\n",buf,bp,str,bp);
if (strcmp(bp,str) != 0)
sysfault("recvstring: MISMATCH\n");
}
void
writer(void)
{
xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
sendstring("hello");
sendstring("world");
sendstring("goodbye");
sendstring("galaxy");
}
void
reader(void)
{
xdrstdio_create(&xdrs, stdin, XDR_DECODE);
recvstring("hello");
recvstring("world");
recvstring("goodbye");
recvstring("galaxy");
}
int
main(int argc,char **argv)
{
int opt_dir = -1;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'r':
opt_dir = 0;
break;
case 'w':
opt_dir = 1;
break;
}
}
switch (opt_dir) {
case 0:
reader();
break;
case 1:
writer();
break;
default:
sysfault("main: -r/-w not specified\n");
break;
}
return 0;
}
Here is the "magic" xdrver.s file:
.globl xdrstdio_create
.symver foo, xdrstdio_create#GLIBC_2.2.5
xdrstdio_create:
jmp foo
.globl xdr_wrapstring
.symver bar, xdr_wrapstring#GLIBC_2.2.5
xdr_wrapstring:
jmp bar
Compile with (e.g.):
cc -o xdrtest xdrtest.c xdrver.s
Or, of course, we can create xdrver.o and link with whatever program we want.
Anyway, to test the program:
./xdrtest -w | ./xdrtest -r
And, the output is:
buf=0x4044a0 bp=0x4044a0 str='hello' bp='hello'
buf=0x4044a0 bp=0x4044a0 str='world' bp='world'
buf=0x4044a0 bp=0x4044a0 str='goodbye' bp='goodbye'
buf=0x4044a0 bp=0x4044a0 str='galaxy' bp='galaxy'
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.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <stdbool.h>
#define PI 3.1415926535898
// the usage
void usage(char *program) {
fprintf(stderr, "\nProgram Usage:\n%s\n", program);
fprintf(stderr,
" [ -n 1000000 ] number of steps per run, default 10000\n");
fprintf(stderr,
" [ -o output.dat ] the output file, default: output.dat\n");
fprintf(stderr, " [ -h ] display this information\n");
fprintf(stderr, "\n");
exit(1);
}
// function to get system arguments from command line
void getMyArgs(int argc, char **argv, int *nstep, char *filename) {
char ch;
while ((ch = getopt(argc, argv, "n:o:h")) != -1) {
switch (ch) {
case 'n':
*nstep = atoi(optarg);
break;
case 'o':
*filename = *optarg;//as if there is the error.
break;
case 'h':
usage(argv[0]);
case '?':
usage(argv[0]);
}
}
}
// function to get the distance from the start point
double dist(double *site) { return sqrt(site[0] * site[0] + site[1] * site[1]); }
// function to output the data
void output(FILE *fp, int istep, double *site) {
fprintf(fp, "%10d %10.2f %10.2f %10.2f\n", istep, site[0], site[1],
dist(site));
}
// function to get the step
void getStep(double *step) {
/* get the degree */
double deg = rand() / (double)RAND_MAX* 2 * PI;
step[0] = sin(deg);
step[1] = cos(deg);
}
// function run the step
void runStep(double *site, double *step,double s) {
site[0] += s*step[0];
site[1] += s*step[1];
}
//probability function
bool proba(double p){
if(rand()/RAND_MAX<p)
return true;
else
return false;
}
// the main program
int main(int argc, char *argv[]) {
// for parameters
int nstep = 1000;
char *filename = "output.dat";
getMyArgs(argc, argv, &nstep, filename);
srand((unsigned)time(0));
// the initial state
double site[] = {0.0, 0.0};
FILE *fp = fopen(filename, "w");
output(fp, 0, site);
// walking ....
int i;
for (i = 1; i <= nstep; ++i) {
double step[2],s=1;
if (proba(0.8)==1)
{
if(proba(0.5)==1)
{
s=0.5;
}
getStep(step);
runStep(site, step,s);
}
output(fp, i, site);
}
fclose(fp);
}
It's my random_walk code. The function should output data.dat when I run ./a.out -n 1000 -o data.dat. But it always results in Segmentation fault (core dumped).
It can output output.dat with 1000 statics when I run ./a.out -n 1000
I guess it should be caused by filename = *optarg, but I can't get it correct.
I have changed my code as #kaylum said.But GCC show me:
random_walk.c: In function ‘getMyArgs’:
random_walk.c:30:17: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
*filename = *optarg;
And I run ./a.out -n 10000 -o data.dat, it results in:
Segmentation fault (core dumped)
Even though we set currentMethod.bytes with local function to generate random numbers, the RAND_bytes is not invoking. After we set RAND_set_rand_method(&cuurentMethod).
Here I attached link [https://github.com/openssl/openssl/blob/master/test/sm2_internal_test.c] which I already tried.
int main()
{
unsigned char rand[16];
int ret;
RAND_METHOD *oldMethod,currentMethod,*temp;
oldMethod = RAND_get_rand_method();/*getting default method*/
currentMethod = *oldMethod;
currentMethod.bytes = local_function_rand;
if((ret = RAND_set_rand_method(¤tMethod))!= 1)
return 0;
/* Now we are printing both address of local_function_method_rand() and
temp->bytes , those address are same after getting. */
temp = RAND_get_rand_method();
/* after we are comparing with RAND_SSLeay() function , to find default or not*/
if((ret = RAND_bytes(rand,16)) != 1)
return 0;
return 1;
}
Expecting result is our local function should invoke. Also, to invoke RAND_bytes() is it required to set fips mode in Linux system?
After cleaning up and minimizing your test program and filling in the missing parts:
#include <openssl/rand.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int local_function_rand(unsigned char *buf, int num) {
printf("in local_function_rand(); requested %d bytes\n", num);
memset(buf, 4, num); // RFC 1149.5 standard random number
return 1;
}
int main(void) {
unsigned char rand[16];
RAND_METHOD currentMethod = {.bytes = local_function_rand};
RAND_set_rand_method(¤tMethod);
if (RAND_bytes(rand, sizeof rand) != 1) {
return EXIT_FAILURE;
}
return 0;
}
and running it (With OpenSSL 1.1.1):
$ gcc -Wall -Wextra rand.c -lcrypto
$ ./a.out
in local_function_rand(); requested 16 bytes
it works as expected; the user-supplied function is being called by RAND_bytes(). If you're getting different results from your code, there's probably a problem in the bits you didn't include in your question.
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.