Makefile in C (ubuntu) multiple definition - c
I am learning c and trying to build using makefile. I am stuck on the following error and don't know what to do next.
the build command is
gcc -o logfind logfind.o cmdargutils.o filesystem_utils.o file_utils.o strutils.o
If I need both file_utils.o and cmdargutils.o but if I add both I get the following error.
error screenshot
ERROR
file_utils.o:(.rodata+0x0): multiple definition of `MAX_LINE'
logfind.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'logfind' failed
make: *** [logfind] Error 1
The source is:
Makefile
logfind: clean logfind.o
gcc -o logfind logfind.o cmdargutils.o filesystem_utils.o file_utils.o strutils.o
logfind.o: logfind.c cmdargutils.o file_utils.o filesystem_utils.o strutils.o error_codes.h
gcc -c logfind.c
cmdargutils.o: cmdargutils.c cmdargutils.h
gcc -c cmdargutils.c
file_utils.o: file_utils.c file_utils.h
gcc -c file_utils.c
filesystem_utils.o: filesystem_utils.c filesystem_utils.h
gcc -c filesystem_utils.c
strutils.o: strutils.c strutils.h
gcc -c strutils.c
clean:
rm -f *.o logfind
cmdargutils.h
#ifndef CMD_ARG_UTILS
#define CMD_ARG_UTILS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include "error_codes.h"
#include "strutils.h"
struct Argument {
bool is_and_operation;
int count;
char **search_terms;
};
struct Argument *argument_create(int argc, char **argv, int start, bool is_and_operation);
void argument_destroy(struct Argument *argument);
struct Argument *parse_arguments(int argc, char **argv);
#endif
error_codes.h
#ifndef ERROR_CODES
#define ERROR_CODES
enum error_codes {
MEMORY_ERROR,
INPUT_ERROR
};
#endif
file_utils.h
#ifndef FILE_UTILS
#define FILE_UTILS
#define _GNU_SOURCE
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "cmdargutils.h"
const size_t MAX_LINE = 1024;
bool is_match(char *, struct Argument *);
bool scan_file(char *, struct Argument *);
#endif
filesystem_utils.h
#ifndef FILESYSTEM_UTILS
#define FILESYSTEM_UTILS
#include <glob.h>
#include <string.h>
#include "strutils.h"
struct SearchFiles {
int count;
char **paths;
};
struct SearchFiles *search_files_create(int count, char** paths);
void search_files_destroy(struct SearchFiles *search_files);
struct SearchFiles *scan_directory(char *directory_path, char *pattern);
#endif
strutils.h
#ifndef STRUTILS
#define STRUTILS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "error_codes.h"
char *strdup(const char *source);
char **copy_string_array(char **source, int start, int end);
#endif
logfind.c
#include <stdio.h>
#include <stdlib.h>
#include <glob.h>
#include "cmdargutils.h"
#include "filesystem_utils.h"
#include "file_utils.h"
int main(int argc, char **argv) {
struct Argument *argument = parse_arguments(argc, argv);
int i = 0;
struct SearchFiles *search_files = scan_directory(".", "*.*");
for(i = 0; i < search_files->count; i++) {
scan_file(search_files->paths[i], argument);
}
search_files_destroy(search_files);
argument_destroy(argument);
return 0;
}
cmdargutils.c
#include "cmdargutils.h"
struct Argument *argument_create(int argc, char **argv, int start, bool is_and_operation){
struct Argument *argument = (struct Argument *)malloc(sizeof(struct Argument));
if(!argument) {
printf("Could not initialize arguments.\n");
exit(MEMORY_ERROR);
}
argument->count = argc - start;
argument->is_and_operation = is_and_operation;
argument->search_terms = copy_string_array(argv, start, argc);
return argument;
}
void argument_destroy(struct Argument *argument){
int i = 0;
for(i = 0; i < argument->count; i++) {
free(argument->search_terms[i]);
}
free(argument->search_terms);
free(argument);
argument = NULL;
}
struct Argument *parse_arguments(int argc, char **argv) {
struct Argument *argument = NULL;
bool is_and_operation = true;
int start = 0;
if(argc < 2) {
printf("Not enough arguments\n");
exit(INPUT_ERROR);
}
char *operation = argv[1];
if(strcmp(operation, "-o") == 0) {
is_and_operation = false;
if(argc < 3) {
printf("Not enough arguments\n");
exit(INPUT_ERROR);
}
}
start = is_and_operation ? 1 : 2;
argument = argument_create(argc, argv, start, is_and_operation);
return argument;
}
file_utils.c
#include "file_utils.h"
bool is_match(char *line, struct Argument *argument) {
int i = 0;
bool isMatch = false;
for(i = 0; i < argument->count; i++) {
char *found = strcasestr(line, argument->search_terms[i]);
if(!found) {
if(argument->is_and_operation) {
isMatch = false;
break;
} else {
continue;
}
} else {
isMatch = true;
if(argument->is_and_operation) {
continue;
} else {
break;
}
}
}
return isMatch;
}
bool scan_file(char *path, struct Argument *argument) {
FILE *file = fopen(path, "r");
int line_number = 0;
char *line = malloc(MAX_LINE);
while(fgets(line, MAX_LINE - 1, file)!= NULL) {
++line_number;
if(is_match(line, argument)) {
printf("%s:%d\n", path, line_number);
printf("\t%s\n", line);
}
}
free(line);
fclose(file);
}
filesystem_utils.c
#include "filesystem_utils.h"
struct SearchFiles *search_files_create(int count, char** paths) {
struct SearchFiles *search_files = (struct SearchFiles *)malloc(sizeof(struct SearchFiles));
search_files->count = count;
search_files->paths = copy_string_array(paths, 0, count);
return search_files;
}
void search_files_destroy(struct SearchFiles *search_files) {
int i = 0;
for(i = 0; i < search_files->count; i++) {
free(search_files->paths[i]);
}
free(search_files->paths);
free(search_files);
search_files = NULL;
}
struct SearchFiles *scan_directory(char *directory_path, char *pattern) {
glob_t globbuf;
int error = glob(pattern, GLOB_MARK, NULL, &globbuf);
if(!error) {
struct SearchFiles *search_files = search_files_create(globbuf.gl_pathc, globbuf.gl_pathv);
globfree(&globbuf);
return search_files;
}
return NULL;
}
strutils.c
#include "strutils.h"
char *strdup(const char *source) {
char *dest = malloc(strlen(source) + 1);
if(!dest) {
printf("Memory allocation error\n");
exit(MEMORY_ERROR);
}
strcpy(dest, source);
return dest;
}
char **copy_string_array(char **source, int start, int end) {
char **dest = (char **)malloc(sizeof(char *) * (end - start));
int di = 0;
int si = start;
for(di = 0, si = start; si < end;
si++, di++) {
dest[di] = strdup(source[si]);
}
return dest;
}
read documentation!
First, take a few hours to read documentation of GNU make, and read how to invoke GCC. You also need to understand more about the preprocessor, so read documentation of cpp. You want to take advantage of builtin GNU make rules (so run make -p to understand them) and variables. See also this answer. You could use remake (as remake -x) to debug your Makefile. You apparently don't understand how make and how gcc should be used, so you need to read more. Read also a C tutorial, look into some C reference, and glance when needed into the C11 standard n1570. Of course, read the documentation of every function you use (e.g. printf(3) etc..). For Linux system programming, read a book like ALP and relevant man pages from syscalls(2) and intro(3) etc...
Then read How to debug small programs. You certainly want to compile with all warnings and debug info.
a better Makefile
You might try something like:
# a better Makefile
# your C compiler
CC= gcc
# the verbose remove
RM= rm -vf
# your C compilation flags
CFLAGS= -Wall -Wextra -g
# your C source files
MY_CSOURCES= logfind.c cmdargutils.c filesystem_utils.c file_utils.c strutils.c
# the corresponding object files
MY_OBJECTS= $(patsubst %.c, %.o, $(MY_CSOURCES))
# the conventional phony targets
.PHONY: all clean
# the only program is for the default target all
all: logfind
logfind: $(MY_OBJECTS)
$(LINK.c) $< -o $#
# cleaning the mess
clean:
$(RM) logfind *.o *~
Of course, you need dependencies for object files on header files. You could compute them automatically, but it is simpler to explicit them, so add something like:
strutils.o: strutils.c strutils.h
and so on for each other object files.
BTW my HelloWorld/ directory on github is a tutorial example for using make
your multiple definition bug
You are getting multiple definition of MAX_LINE because it is defined in a header file included by several translation units, hence several translation units define it.
So either make it a preprocessor constant #define MAX_LINE 1024 in your header file_utils.h, or put there only a declaration like extern const int MAX_LINE; and define it only once in a single translation unit, as const int MAX_LINE=1024; in file_utils.c
general hints
I strongly recommend doing some iterative and incremental development: code only one or two dozen lines at once, then compile them, improve them to get no warnings, debug them with the GDB debugger and test them. At last repeat all this till satisfied. I do recommend using also a version control system (like git) even for school homework.
You might want to use valgrind to hunt memory leaks and other dynamic memory allocation bugs.
You could also use some static source analyzer like clang-analyzer or even Frama-C.
Once your program is debugged, you might add optimization flags like -O2 into your CFLAGS (in particular if you benchmark it with time(1)).
You could be interested by ntfw(3).
Related
How to properly link libraries with gcc
I have 2 libraries made from scratch in c, vector.h and string.h with the source file string.c (the vector.h only has define directives, no need for source file), and used the #pragma once directive so that the header files would only be included one time. The string library uses the vector library, and then both are included in main.c. With that setup, i ran into two problems: if i simply did gcc main.c -o build/main.exe, it couldn't find the function definitions in string.c for the function declarations in string.h (undefined reference to `stringFunction') if i first compiled the source files into objects, and then compiled them into the executable (gcc -c string/string.c -o build/obj/string.o, gcc -c main.c -o build/obj/main.o, gcc -o build/main.exe build/obj/main.o build/obj/string.o, ./build/main.exe), it said there were multiple definitions of the same functions (build/obj/string.o: in function `vectorCreate_String': string.c:(.text+0x0): multiple definition of `vectorCreate_String'; build/obj/main.o:main.c:(.text+0x0): first defined here) Folder structure: PROJECT - string - string.c - string.h - vector - vector.h - main.c vector.h #pragma once #include <stdlib.h> #define DEFINE_VECTOR(type) typedef struct { \ unsigned int size; \ size_t bytesize; \ type *data; \ } Vector_##type; \ Vector_##type *vectorCreate_##type(unsigned int initialSize, type *initialElements) { \ Vector_##type *v = (Vector_##type*)malloc(sizeof(Vector_##type)); \ v->size = initialSize; \ v->bytesize = initialSize * sizeof(type); \ v->data = (type*)malloc(v->bytesize); \ for (unsigned int i=0; i<initialSize; i++) v->data[i] = initialElements[i]; \ return v; \ } \ void vectorPush_##type(Vector_##type *v, type element) { \ v->size++; \ v->bytesize += sizeof(type); \ v->data = (type*)realloc(v->data, v->bytesize); \ v->data[v->size-1] = element; \ } \ void vectorFree_##type(Vector_##type *v) { \ free(v->data); \ free(v); \ } \ Vector_##type *vectorSlice_##type(Vector_##type *v, unsigned int start, unsigned int end) { \ Vector_##type *slice = (Vector_##type*)malloc(sizeof(Vector_##type)); \ slice->size = end - start; \ slice->bytesize = slice->size * sizeof(type); \ slice->data = (type*)malloc(slice->bytesize); \ for (unsigned int i=0; i<slice->size; i++) slice->data[i] = v->data[start + i]; \ return slice; \ } #define Vector(type) Vector_##type #define vectorCreate(type, initialSize, initialElements) vectorCreate_##type(initialSize, initialElements) #define vectorPush(type, vector, element) vectorPush_##type(vector, element) #define vectorFree(type, vector) vectorFree_##type(vector) #define vectorSlice(type, vector, start, end) vectorSlice_##type(vector, start, end) string.h #pragma once #include "../vector/vector.h" typedef struct { unsigned int length; char *str; } String; DEFINE_VECTOR(String); String *stringCreate(char *str); String *stringAppend(String *string, char *str); void stringFree(String *string); String *stringSlice(String *string, unsigned int start, unsigned int end); Vector(String) *stringSplit(String *string, char *delimiter); string.c #include "string.h" #include <stdio.h> #include <stdlib.h> #include <string.h> String *stringCreate(char *str) { String *string = malloc(sizeof(String)); string->length = strlen(str); string->str = malloc(string->length + 1); strcpy(string->str, str); return string; } String *stringAppend(String *string, char *str) { string->length += strlen(str); string->str = realloc(string->str, string->length + 1); strcat(string->str, str); return string; } void stringFree(String *string) { free(string->str); free(string); } String *stringSlice(String *string, unsigned int start, unsigned int end) { String *newString; newString->length = end - start; newString->str = malloc(newString->length + 1); for (unsigned int i=0; i<newString->length; i++) newString->str[i] = string->str[start + i]; newString->str[newString->length] = '\0'; return newString; } // not implemented yet Vector(String) *stringSplit(String *string, char *delimiter) { return NULL; } main.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include "./string/string.h" // stuff to test if everything is working properly int main(int argc, char *argv[]) { Vector(String) *strings = vectorCreate(String, 0, NULL); vectorPush(String, strings, *stringCreate("Hello")); vectorPush(String, strings, *stringCreate("World")); printf("%s %s\n", strings->data[0].str, strings->data[1].str); vectorFree(String, strings); return 0; }
A "function declaration" is usually put into a .h file. A "function definition" is usually put into a .c file. DEFINE_VECTOR provides function definitions and you use it in string.h. Which means the function vectorCreate_String() for example is defined both in string.c and main.c due to both including string.h. I suggest you add another macro in vector.h that only generates function declarations and move that typedef struct from DEFINE_VECTOR to that macro. Use that macro in string.h, and then use DEFINE_VECTOR in string.c to provide definitions for the declared functions in string.h.
How to hide execl() arguments from ps?
How to hide/change a process argument after execl()? or how can we hide/change arguments of a child process that is using system() / execl()? Working on SHC (the purpose of this application is to compile a bash script into a binary) i am using execl() function to execute the sh script; The problem is that execl() argument are exposed to ps; the purpose of this question is to make SHC just a little bit more reliable and solve some issues reported by users. #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc,char* argv[]){ int runThis; //Create child process if(fork() == 0){ printf("I'm the child\n"); //runThis = system("echo test; sleep 30"); runThis = execl("/bin/sh", "sh", "-c", "echo test; sleep 30", (char *) 0); exit(0); } else { printf("I'm the parent.\n"); } printf("Continue main\n"); return 0; } When running this code, sh -c echo test; sleep 30 is exposed to ps Solution attempt 1: successful but not reliable Hiding commands arguments with ld_preload can be done with this solution or by using setenv("LD_PRELOAD","myLib.so",1); (dlopen() will not work with execl()), this solution require indeed loading a library to our application. Solution attempt 2: semi successful Wrapping __libc_start_main with ld --wrap=symbol, this works for parent but the code is not wrapped after execl() / system() #include <stdlib.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <unistd.h> int __real___libc_start_main(int (*main) (int, char **, char **), int argc, char **ubp_av, void (*init) (void), void (*fini)(void), void (*rtld_fini)(void), void (*stack_end)); int __wrap___libc_start_main(int (*main) (int, char **, char **), int argc, char **ubp_av, void (*init) (void), void (*fini)(void), void (*rtld_fini)(void), void (*stack_end)) { printf("Main called\n"); //ubp_av[1] = "test"; int result = __real___libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end); return result; } Build commands: (wrap.c is the code above and example.c is the first code sample) gcc -c example.c -o 1.o; gcc -c wrap.c -o 2.o; gcc -Wl,-wrap,__libc_start_main -Wl,-wrap=__libc_start_main 1.o 2.o -o myapp Solution attempt 3: semi successful Similar to attempt 2, it consist of linking the code of attempt 1 at build time... but this does not work with execl() build the library as libfoo or an other name gcc -Wall -O2 -fpic -shared -Wl,-soname,libfoo.so -ldl -o libfoo.so wrap.c (wrap.c is the code from attempt 1) install it sudo ln -s /path/libfoo.so /usr/lib64/libfoo.so link it gcc example.c -o myapp -L.. -lfoo Solution attempt 4: related but not useful here Ptrace can be used from the parent process to modify the child argument after execl() example-1 example-2
Alternative solution: Bash content can be piped and thus hidden from ps script="script goes here" echo $script | bash Mitigated solution: This is not a perfect solution, but it will answer the question, this code will create an shc_x.c under /tmp build it, then preload it with environment variable. shc_x.c, inject the bash sh content to ******** argument by replacing it and change the location of child commands arguments and thus hide them from ps as well. shc_x.c: (this file is generated with the second code) /* * Copyright 2019 - Intika <intika#librefox.org> * Replace ******** with secret read from fd 21 * Also change arguments location of sub commands (sh script commands) * gcc -Wall -fpic -shared -o shc_secret.so shc_secret.c -ldl */ #define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */ #define PLACEHOLDER "********" #include <dlfcn.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdio.h> #include <signal.h> static char secret[128000]; //max size typedef int (*pfi)(int, char **, char **); static pfi real_main; // copy argv to new location char **copyargs(int argc, char** argv){ char **newargv = malloc((argc+1)*sizeof(*argv)); char *from,*to; int i,len; for(i = 0; i<argc; i++){ from = argv[i]; len = strlen(from)+1; to = malloc(len); memcpy(to,from,len); // zap old argv space memset(from,'\0',len); newargv[i] = to; argv[i] = 0; } newargv[argc] = 0; return newargv; } static int mymain(int argc, char** argv, char** env) { //fprintf(stderr, "Inject main argc = %d\n", argc); return real_main(argc, copyargs(argc,argv), env); } int __libc_start_main(int (*main) (int, char**, char**), int argc, char **argv, void (*init) (void), void (*fini)(void), void (*rtld_fini)(void), void (*stack_end)){ static int (*real___libc_start_main)() = NULL; int n; if (!real___libc_start_main) { real___libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main"); if (!real___libc_start_main) abort(); } n = read(21, secret, sizeof(secret)); if (n > 0) { int i; if (secret[n - 1] == '\n') secret[--n] = '\0'; for (i = 1; i < argc; i++) if (strcmp(argv[i], PLACEHOLDER) == 0) argv[i] = secret; } real_main = main; return real___libc_start_main(mymain, argc, argv, init, fini, rtld_fini, stack_end); } On the main c application: static const char * shc_x[] = { "/*", " * Copyright 2019 - Intika <intika#librefox.org>", " * Replace ******** with secret read from fd 21", " * Also change arguments location of sub commands (sh script commands)", " * gcc -Wall -fpic -shared -o shc_secret.so shc_secret.c -ldl", " */", "", "#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */", "#define PLACEHOLDER \"********\"", "#include <dlfcn.h>", "#include <stdlib.h>", "#include <string.h>", "#include <unistd.h>", "#include <stdio.h>", "#include <signal.h>", "", "static char secret[128000]; //max size", "typedef int (*pfi)(int, char **, char **);", "static pfi real_main;", "", "// copy argv to new location", "char **copyargs(int argc, char** argv){", " char **newargv = malloc((argc+1)*sizeof(*argv));", " char *from,*to;", " int i,len;", "", " for(i = 0; i<argc; i++){", " from = argv[i];", " len = strlen(from)+1;", " to = malloc(len);", " memcpy(to,from,len);", " // zap old argv space", " memset(from,'\\0',len);", " newargv[i] = to;", " argv[i] = 0;", " }", " newargv[argc] = 0;", " return newargv;", "}", "", "static int mymain(int argc, char** argv, char** env) {", " //fprintf(stderr, \"Inject main argc = %d\\n\", argc);", " return real_main(argc, copyargs(argc,argv), env);", "}", "", "int __libc_start_main(int (*main) (int, char**, char**),", " int argc,", " char **argv,", " void (*init) (void),", " void (*fini)(void),", " void (*rtld_fini)(void),", " void (*stack_end)){", " static int (*real___libc_start_main)() = NULL;", " int n;", "", " if (!real___libc_start_main) {", " real___libc_start_main = dlsym(RTLD_NEXT, \"__libc_start_main\");", " if (!real___libc_start_main) abort();", " }", "", " n = read(21, secret, sizeof(secret));", " if (n > 0) {", " int i;", "", " if (secret[n - 1] == '\\n') secret[--n] = '\\0';", " for (i = 1; i < argc; i++)", " if (strcmp(argv[i], PLACEHOLDER) == 0)", " argv[i] = secret;", " }", "", " real_main = main;", "", " return real___libc_start_main(mymain, argc, argv, init, fini, rtld_fini, stack_end);", "}", "", 0}; #include <sys/stat.h> #include <sys/types.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <signal.h> #include <sys/prctl.h> #define PR_SET_PTRACER 0x59616d61 #include <stddef.h> #include <sys/syscall.h> #include <sys/socket.h> #include <linux/filter.h> #include <linux/seccomp.h> #include <linux/audit.h> void shc_x_file() { FILE *fp; int line = 0; if ((fp = fopen("/tmp/shc_x.c", "w")) == NULL ) {exit(1); exit(1);} for (line = 0; shc_x[line]; line++) fprintf(fp, "%s\n", shc_x[line]); fflush(fp);fclose(fp); } int make() { char * cc, * cflags, * ldflags; char cmd[4096]; cc = getenv("CC"); if (!cc) cc = "cc"; sprintf(cmd, "%s %s -o %s %s", cc, "-Wall -fpic -shared", "/tmp/shc_x.so", "/tmp/shc_x.c -ldl"); if (system(cmd)) {remove("/tmp/shc_x.c"); return -1;} remove("/tmp/shc_x.c"); return 0; } int main(int argc, char ** argv) { shc_x_file(); if (make()) {exit(1);} setenv("LD_PRELOAD","/tmp/shc_x.so",1); // rest of the code execl etc... } Note: arguments can always be recovered by many ways, this code just makes it a little bit more complicated to reverse.
Why using crypt in glibc cause compiler warning?
I tried to compiler the following code(minimum example, see the edit for the whole code): // a.c #include <stdio.h> #define _XOPEN_SOURCE #include <unistd.h> int main(int argc, char* argv[]) { puts((const char*) crypt("AAAA", "$6$2222")); return 0; } Using clang-7 -lcrypt a.c and it emitted the following warning: minimum.c:8:24: warning: implicit declaration of function 'crypt' is invalid in C99 [-Wimplicit-function-declaration] puts((const char*) crypt("AAAA", "$6$2222")); ^ minimum.c:8:10: warning: cast to 'const char *' from smaller integer type 'int' [-Wint-to-pointer-cast] puts((const char*) crypt("AAAA", "$6$2222")); ^ 2 warnings generated. But ./a.out did seem to work: $6$2222$6GKY4KPtBqD9jAhwxIZGDqEShaBaw.pkyJxjvSlKmtygDXKQ2Q62CPY98MPIZbz2h6iMCgLTVEYplzp.naYLz1 I found out that if I remove #include <stdio.h> and puts like this: // new_a.c #define _XOPEN_SOURCE #include <unistd.h> int main(int argc, char* argv[]) { crypt("AAAA", "$6$2222"); return 0; } Then there is no warnings. How to fix these warnings without removing #include <stdio.h>? Edit: Whole program: #include <stdio.h> #include <stdlib.h> #include <string.h> #define _X_OPEN_SOURCE #include <unistd.h> #include <assert.h> void* Calloc(size_t cnt, size_t size) { void *ret = calloc(cnt, size); assert(ret); return ret; } size_t GetSaltLen(const char *salt) { size_t salt_len = strlen(salt); assert(salt_len > 0); assert(salt_len <= 16); return salt_len; } char* GetSaltAndVersion(const char version, const char *salt) { size_t saltlen = GetSaltLen(salt); /* * The format of salt: * $one_digit_number$up_to_16_character\0 * For more info, check man crypt. */ char *ret = (char*) Calloc(1 + 1 + 1 + saltlen + 1, sizeof(char)); char *beg = ret; *beg++ = '$'; *beg++ = version; *beg++ = '$'; memcpy((void*) beg, (const void*) salt, saltlen + 1); return ret; } void crypt_and_print(const char *passwd, const char *salt_and_version) { char *result = crypt(passwd, salt_and_version); assert(puts(result) != EOF); } int main(int argc, char* argv[]) { if (argc != 4) { fprintf(stderr, "argc = %d\n", argc); return 1; } char *salt_and_version = GetSaltAndVersion(argv[2][0], argv[3]); crypt_and_print(argv[1], salt_and_version); free(salt_and_version); return 0; } I have tried as #Andrey Akhmetov suggested and put the #define onto the first line, but the warnings did not disappear.
The macro _XOPEN_SOURCE is documented in feature_test_macros(7). In particular, the manpage states: NOTE: In order to be effective, a feature test macro must be defined before including any header files. This can be done either in the compilation command (cc -DMACRO=value) or by defining the macro within the source code before including any headers. When you include stdio.h, you indirectly include features.h, which uses the feature test macros as defined at that point. In particular, since _XOPEN_SOURCE and friends aren't defined at that point, crypt.h does not declare crypt. By the time you define _XOPEN_SOURCE it is too late, since features.h has an include guard preventing it from being included twice. By swapping the order of the first two lines, the code works without raising this warning on my system: #define _XOPEN_SOURCE #include <stdio.h> #include <unistd.h> int main(int argc, char* argv[]) { puts((const char*) crypt("AAAA", "$6$2222")); return 0; } Your larger example does not work for a second reason: You wrote _X_OPEN_SOURCE as the name of the macro, while the correct name is _XOPEN_SOURCE.
Realloc using extern
Hi im trying to figure out how to use realloc. I have made a small test project that im trying to malloc for the creation of the first element in main, followed by adding a number to that location then reallocating the array to hold one more element. Main.c #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]){ int i =0; int *fileTest = (int*) malloc(sizeof(char * )); int amtFiles=0; for(i=0;i<3;i++){ parseInput(fileTest , amtFiles); printf("%d", fileTest[1]); } } parse.c #include <stdlib.h> #include "stddef.h"; #include <stdlib.h> extern int parseInput(int *fileTest,int amtFiles){ printf("enter number"); scanf("%d",amtFiles); fileTest = realloc(fileTest, (amtFiles * sizeof(char *))); } makefile CC = gcc CC_FLAGS = -g -ansi -pedantic -Wall -w FILES = main.c parse.c OUT_EXE = Test2 build: $(FILES) $(CC) $(CC_FLAGS) -o $(OUT_EXE) $(FILES) clean: rm -f *.o core *.exe *~ rebuild: clean build
C is pass by value. You should return the pointer value. Otherwise the original one is unchanged. So from parseInput return the pointer or pass address of the variable and change it accordingly (not shown in example). While reallocating use another pointer variable other than the original one, in case of failure you don't lose reference to the old memory. Don't print uninitialized value. (in main()). Don't cast the return value of malloc. When printing a pointer do this printf("%p",(void*)fileTest[1]);. Also you should put the extern declaration in main.c. You have passed incorrect number of arguments to the parseInput function. The code didn' compile. Then after correcting the input - if you try then you might get segmentation fault or some similar error. I have tried demonstrating something over here. The naming can be much more better. I have tried to keep the general aspects of what you have tried. Multiple source file with realloc used and tested, working with pointers etc. main.c #include <stdio.h> #include <stdlib.h> #include "myheader.h" int main(void) { int *fileTest = NULL; int amtFiles; int weTried = 2; while(weTried --> 0){ printf("%s\n", "Enter the array size.\n"); if( scanf("%d",&amtFiles) != 1){ fprintf(stderr, "%s\n","Error in input" ); exit(1); } else if( amtFiles <= 0){ fprintf(stderr, "%s\n", "Enter positive integral value"); exit(1); } fileTest = parseInput(fileTest, amtFiles); if( fileTest == NULL){ fprintf(stderr, "%s\n","Realloc failed." ); exit(1); } for(int i = 0; i < amtFiles; i++){ printf("[%d]\n",fileTest[i]); } } return 0; } parse.c #include <stdlib.h> #include <stdio.h> #include "myheader.h" int* parseInput(int *fileTest,int amtFiles) { if( amtFiles <= 0){ fprintf(stderr, "%s\n", "Error in number of inputs"); exit(1); } int *t = realloc(fileTest, (amtFiles * sizeof * t)); if( t == NULL ){ fprintf(stderr, "%s\n", "Execution exception"); return NULL; } fileTest = t; for(int i = 0; i < amtFiles; i++){ fileTest[i] = 2017+i; } return fileTest; } myheader.h extern int* parseInput(int *,int ); Compiled and run gcc -Wall -Wextra -Werror main.c parse.c ./a.out
undefined reference.. linker command failed with exit code 1
I want to create a shell file using the c language programming. I have this scheleton given already by the professor, but wen I try to executed I have this error and I have this problem the myshell.c file (and this file is the one that I have to modify and execute) /* RCS information: $Id: myshell.c,v 1.2 2006/04/05 22:46:33 elm Exp $ */ #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> extern char **getcmdstring(char *cmd); int main(void) { int i; char **args; char cmd[4096]; while(1) { printf("$ "); fgets(cmd,4096,stdin); args = getcmdstring(cmd); for(i = 0; args[i] != NULL; i++) { printf("Argument %d: %s\n", i, args[i]); } } } and the shell.l file /* RCS information: $Id: shell.l,v 1.1 2006/04/05 22:46:33 elm Exp $ */ #include <stdio.h> #include <strings.h> #include <string.h> int _numargs = 200; char *_args[200]; int _argcount = 0; char *strdup(const char *); %} WORD [a-zA-Z0-9\/\.-]+ SPECIAL [()><|&;] %% _argcount = 0; _args[0] = NULL; {WORD}|{SPECIAL} { if(_argcount < _numargs-1) { _args[_argcount++] = (char *)strdup(yytext); _args[_argcount] = NULL; } } \n return (int)_args; [ \t]+ . %% char **getcmdstring(char *cmd) { char **ret; yy_scan_string(cmd); ret = (char **)yylex(); yy_delete_buffer(YY_CURRENT_BUFFER); return ret; }
The missing function is included in the shell.l source. This is a source for a lexical analyzer. You need to build the shell.o object file from shell.l. This can be done by creating the C source flex -o shell.c shell.l and then compiling clang shell.c myshell.c -o myshell -ll