How to link main with made libraries? - c

I'm trying to link libraries I made to main source code, but it throws this error. I've been searching for last two hours how to fix this but nothing worked for me.
Compiling:
cd "c:\Users\miros\OneDrive\Documents\C codes\labovi"
gcc 01main.c -o 01main
.\01main
d:/programs/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\miros\AppData\Local\Temp\ccGHtHKg.o:01main.c:(.text+0x46): undefined reference to 'faktorijel'
d:/programs/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\miros\AppData\Local\Temp\ccGHtHKg.o:01main.c:(.text+0x72): undefined reference to 'suma'
collect2.exe: error: ld returned 1 exit status
01ucitavanje.h
#ifndef UCITAVANJE_H
#define UCITAVANJE_H
#include <stdio.h>
#include <stdlib.h>
long long *niz;
int n;
void ucitavanje();
#endif
01ucitavanje.c
#include "01ucitavanje.h"
void ucitavanje(){
scanf("%d", &n);
niz = malloc(sizeof(long long) * n);
for (int i = 0; i < n; i++)
scanf("%d", niz + i);
}
01izracunavanje.h
#ifndef IZRACUNAVANJE_H
#define IZRACUNAVANJE_H
#include <stdio.h>
long long faktorijel(int n);
long long suma(long long *niz, int n);
#endif
01izracunavanje.c
#include "01izracunavanje.h"
long long faktorijel(int n){
long long f;
for (int i = 2; i <= n; i++)
f *= i;
return f;
}
long long suma (long long *niz, int n){
long long s = niz[0];
for (int i = 1; i < n; i++)
s += niz[i];
return s;
}
main.c
#include "01izracunavanje.h"
#include "01ucitavanje.h"
int main(){
ucitavanje();
for (int i = 0; i < n; i++)
niz[i] = faktorijel((int)niz[i]);
printf("%d", suma(niz, n));
free(niz);
return 0;
}

You're compiling only main.c into the executable, so the other functions aren't available.
You need to compile each source file into an object file, then link the object files together.
gcc -c main.c
gcc -c 01izracunavanje.c
gcc -c 01ucitavanje.c
gcc -o 01main main.o 01izracunavanje.o 01ucitavanje.o

I'm going to give you a mid-line correction because you put your compilation on one very long line.
In this case, you pass all your .c files to gcc. From
{ gcc 01main.c -o 01main }
We'd rather write
{ gcc -o 01main 01main.c 01izracunavanje.c 01ucitavanje.c }
Since you're not actually building a distribution library but rather a bunch of source files we just compile them all together. It generates better code that way anyway once you start optimizing.
Order of .c files doesn't really matter, but the file containing main is first by tradition. Putting -o before the first .c file used to matter and most people still do it.

Related

multifile direct compile ok, direct compile error

There are 3 files(generator.c, generator.h and main.c).
generator.c: There is only 1 function (gen fun) which is used to generate an array to store 10 random-generate numbers in generator.c.
generator.h:Declaration of generator.c.
main.c: There is only 1 function (main fun) in main.c which is used to print the number generated previously.
If generator.c is included in main.c and I compile it directly by execute "gcc main.c". The result is ok.
But while I compile it using " gcc -c generator.h, gcc -c main.c, gcc generator.o main.o ", it reported a warning "warning: assignment makes pointer from integer without a cast" at " p = gen(arr); " sentence in main funciton. And the final result was "Segmentation fault (core dumped)". The debug information showed "Cannot access memory at address" if i try to visit the value of pointer *p(i.e. array[0]) in the while loop of main function.
//////generator.c///////
int * gen( int arr[])
{
int i = 0;
int * p = arr;
int len = 10;
srand( (unsigned)((time)(NULL)));
while (i< len)
{
*p = rand() % ( len +1) + 0;
i ++;
p++;
}
return arr;
}
//////generator.h//////
int * gen( int arr[]);
//////main.c///////
int main(void)
{
int i = 0;
int arr[10]={0};
int * p;
p = gen(arr);
while (i < 10)
{
printf("output is %d\n",*p);// Segmentation fault (core dumped)
i++;
p++;
}
return 0;
}
Based on the addition to your question, it appears you are confused about how to include generator.h and then to compile the code. First your generator.h should be:
//////generator.h//////
#ifndef GENERATOR_H
#define GENERATOR_H 1
int *gen (int arr[]);
#endif
(edit: added appropriate Header Guards to prevent multiple inclusion of generator.h)
Your generator.c would then be:
//////generator.c///////
#include <stdlib.h>
#include "generator.h"
int *gen (int arr[])
{
int i = 0;
int * p = arr;
int len = 10;
while (i< len)
{
*p = rand() % len + 1;
i ++;
p++;
}
return arr;
}
And finally your main.c (I called it gen.c) would be:
//////main.c///////
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "generator.h"
int main(void)
{
int i = 0;
int arr[10]={0};
int *p;
srand( (unsigned)((time)(NULL)));
p = gen(arr);
while (i < 10)
{
printf ("output is %d\n",*p);
i++;
p++;
}
return 0;
}
Compile
$ gcc -Wall -Wextra -pedantic -std=c11 -Ofast generator.c -o bin/gen gen.c
(note: I would also encourage adding -Wshadow as a normal part of your compile string as well to identify any shadowed variables)
Example Use/Output
$ ./bin/gen
output is 8
output is 1
output is 5
output is 4
output is 9
output is 5
output is 4
output is 6
output is 5
output is 6
Look things over and let me know if you have further questions.

Invalid conversion 'void*' to 'struct*' [duplicate]

This question already has answers here:
malloc - invalid conversion from void* to double*
(2 answers)
Closed 4 years ago.
I'm beginner in C. I'm trying to practice with solving some problems. And I'm getting this error when I compile my code.
[Error] invalid conversion from 'void*' to 'triangle*' [-fpermissive]
The code and purpose is explained below.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct triangle
{
int a;
int b;
int c;
};
typedef struct triangle triangle;
//sort_by_area() function is here
int main()
{
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}
As you can see I have structure and I tried to allocate memory for it with the quantity of input. And try to use it for sort_by_area function. But the problem is triangle *tr = malloc(n * sizeof(triangle)); line gives me the error mentioned above.
Also this code is working for online compilers. I tried to run this code on DEV C++ with default settings. I don't know about the versions and changing the versions of my compiler. I don't even know whether it is about the compiler version. But I am wondering why I'm getting this error. What is the logic behind.
This looks like C code, but you're compiling with a C++ compiler. As such, it complains on the line you mentioned because malloc returns a void * but you're assigning the result to a triangle *.
In C++ an explicit cast is required for this. In C, a void * may be implicitly converted to or from any object pointer type.
Since this appears to be C code and not C++ code, you should compile with a C compiler.
You compile this program as C++ program and this implicit conversion is not allowed in C++.
As I know dev C++ uses MinGW and you may use -xc option to compile program as C program or Settings -> language standard -> and choose the language standard needed
The code looks like C code but you are compiling it with C++ compiler.
Make sure that the file has proper extension for C++(not .c extension).
malloc() returns a (void *) pointer by default, so you have to explicitly cast the (void *) to (triangle *) in your code.
But if you are writing C++ code then I would recommend not to use malloc and free, instead try to use "new" operator in C++ since while instantiating objects it will call the constructors as well(unlike in malloc).
So to avoid complications go with new and delete in C++.
The code in C should look like (file a.c)
Compile using: gcc a.c -o a.o
Run using : ./a.o
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct triangle {
int a;
int b;
int c;
};
typedef struct triangle triangle;
int main() {
int n;
scanf("%d", &n);
triangle *tr = (triangle *)malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
//sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
free(tr);
return 0;
}
The same code in C++ would look like (file a.cpp)
Compile using: g++ a.cpp -o a.o
Run using : ./a.o
#include <iostream>
using namespace std;
struct triangle {
int a;
int b;
int c;
};
int main() {
int n;
cin >> n;
triangle *tr = new triangle[n];
for (int i = 0; i < n; i++) {
cin >> tr[i].a >> tr[i].b >> tr[i].c;
}
// sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
cout << tr[i].a << " " << tr[i].b << " " << tr[i].c << "\n";
}
delete [] tr;
return 0;
}
triangle *tr = (triangle*)malloc(n * sizeof(triangle));
Change the line as shown above. malloc returns generic pointer, so you need to explicitly typecast it to your desired pointer.
Refer this

Fail to link c code to lapack / blas : undefined reference

i have been trying for hours and it drives me crazy. The last error I get is :
demo_cblas.c:(.text+0x83): undefined reference to `clapack_sgetrf'
demo_cblas.c:(.text+0xa3): undefined reference to `clapack_sgetri'
I am compiling the code using
/usr/bin/gcc -o demo_cblas demo_cblas.c -L /usr/lib64 -l :libgfortran.so.3 -L /usr/lib64 \
-llapack -L /usr/lib64 -lblas
I try with and without libgfortran, with different compilers gcc-33, gcc-47, gcc-48. The test code is not from me but comes from this forum ...
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "clapack.h"
#include "cblas.h"
void invertMatrix(float *a, unsigned int height){
int info, ipiv[height];
info = clapack_sgetrf(CblasColMajor, height, height, a, height, ipiv);
info = clapack_sgetri(CblasColMajor, height, a, height, ipiv);
}
void displayMatrix(float *a, unsigned int height, unsigned int width)
{
int i, j;
for(i = 0; i < height; i++){
for(j = 0; j < width; j++)
{
printf("%1.3f ", a[height*j + i]);
}
printf("\n");
}
printf("\n");
}
int main(int argc, char *argv[])
{
int i;
float a[9], b[9], c[9];
srand(time(NULL));
for(i = 0; i < 9; i++)
{
a[i] = 1.0f*rand()/RAND_MAX;
b[i] = a[i];
}
displayMatrix(a, 3, 3);
return 0;
}
I am on Suse 12.3 64bits. In /usr/lib64 I have liblapack.a liblapack.so, ... and libblas.a libblas.so, ... and libgfortran.so.3
The same code without the function "invertMatrix" (the one using the library) compiles fine.
Any idea or suggestion ?
Thank you all for your help.
Vava
I'm quite positive that you also need to link to libcblas, which is the c wrapper library for libblas. Note that libblas is a FORTRAN library which therefore does not contain the function clapack_* you're calling.
I've just got this working on FreeBSD with:
gcc -o test test.c \
-llapack -lblas -lalapack -lcblas
I'd installed math/atlas (from ports) and the lapack and blas packages.
See my question here

Why are my max and min int not working when I compile my program?

I don't understand why I am getting the error:
~/SecureSoftware$ gcc AddNumTest.c
AddNumTest.c:11:0: warning: "INT_MAX" redefined [enabled by default]
/usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed/limits.h:121:0: note: this is the location of the previous definition
I am looking for a way to not crash my program when a big number is added in the command line.
#include<stdio.h>
#include <stdlib.h>
#include <limits.h>
#define INT_MAX (2147483647)
#define INT_MIN (-2147483647)
int main(int argc, char** argv)
{
int i, TotalOfNumbers = 0;
for (i = 1; i < argc; i++)
{
TotalOfNumbers += atoi(argv[i]);
printf("Total of numbers entered = %d\n", TotalOfNumbers);
}
return 0;
}
Redefining INT_MIN and INT_MAX doesn't change the actual limits, it just makes the constants describing them inaccurate.
The limits are based on your platform's integer sizes / widths. To have genuinely different limits, you need to use different data types (for instance, long rather than int).
If a long isn't big enough, you may need to move up further, to a long long; note that these aren't specified prior to the C99 standard, so you need to have a reasonably modern compiler.
Changing your program to use longs instead of ints would look like this:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char** argv)
{
long long i, TotalOfNumbers = 0;
for (i = 1; i < argc; i++)
{
TotalOfNumbers += atoll(argv[i]);
printf("Total of numbers entered = %lld\n", TotalOfNumbers);
}
return 0;
}
Here is the correct way to convert text to integers in C: unlike atoi, strtol will actually tell you if the number is too large, although in a somewhat awkward fashion.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
long
reliable_atol(const char *s)
{
char *endp;
long rv;
errno = 0;
rv = strtol(s, &endp, 10);
if (errno || endp == s || *endp) {
fprintf(stderr, "number malformed or out of range: %s\n", s);
exit(1);
}
return rv;
}
Use this function instead of atoi in your code, and change TotalOfNumbers to long (and print it with %ld).
You might also want to try to detect overflow in the addition, but you can do that without using INT_MAX or INT_MIN:
int main(int argc, char **argv)
{
int i;
long TotalOfNumbers = 0;
for (i = 1; i < argc; i++) {
long n = reliable_atol(argv[i]);
long sum = (long) ((unsigned long)TotalOfNumbers + (unsigned long)n);
if ((n > 0 && sum < TotalOfNumbers) || (n < 0 && sum > TotalOfNumbers)) {
fputs("numeric overflow while computing sum\n", stderr);
exit(2);
}
TotalOfNumbers = sum;
}
printf("total %ld\n", TotalOfNumbers);
return 0;
}
The casts are required, because signed integer overflow provokes undefined behavior but unsigned integer overflow doesn't. This code technically won't work on a non-twos-complement CPU but nobody has manufactured one of those in decades and the C standard's continued provision for the possibility is getting decidedly silly.
If I stick the above two code samples together, making a complete program, I get this for your test case:
$ gcc -O2 -Wall test.c # default mode for this CPU+OS: long is 64 bits
$ ./a.out 22220020202 45
total 22220020247
$ gcc -O2 -Wall -m32 test.c # alternative mode: long is 32 bits
$ ./a.out 22220020202 45
number malformed or out of range: 22220020202

Linking C code with Cuda code

So I'm writing a very basic CUDA code (vector addition) to teach myself the basics of CUDA programming. I've got it working when I write one .cu file, but now I am trying to make it work with a .c and .cu file linked together. My main.c file is as follows:
#include "Test.h"
#include <stdlib.h>
int main(int argc, char *argv[]) {
int n = 1000;
size_t size = n * sizeof(float);
int i;
float *h_a = malloc(size), *h_b = malloc(size), *h_c = malloc(size);
for(i = 0; i < n; i++) {
h_a[i] = h_b[i] = i;
}
addVec(h_a, h_b, h_c, n);
exit(0);
}
Here, Test.h simply says:
void addVec(float *, float *, float *, int);
My vecAdd.cu file says:
#include "Test.h"
__global__ void vecAdd(float *a, float *b, float *c, int n) {
int i = blockDim.x * blockIdx.x + threadIdx.x;
if(i < n)
c[i] = a[i] + b[i];
}
void addVec(float *a, float *b, float *c, int n) {
float *d_a, *d_b, *d_c;
size_t size = n * sizeof(float);
cudaMalloc(&d_a, size);
cudaMalloc(&d_b, size);
cudaMalloc(&d_c, size);
...
}
I then run the commands:
gcc -c -Wall -O3 main.c -o ../obj/main.o
nvcc -c -O3 vecAdd.cu -o ../obj/vecAdd.o
gcc -L/usr/local/cuda/lib64 -lcudart ../obj/main.o ../obj/vecAdd.o -o ../bin/nvTest
The first two work fine. The last one, when I try to link the two object files, tells me that I have an undefined reference to addVec, though it is defined in vecAdd.cu... what am I doing wrong?
You have a C/C++ linkage problem that is basically identical to that described here. This is because nvcc is using a c++ compiler for host code (creating c++ style linkage references i.e. "mangling") and gcc is interpreting main.c as a c (not c++) file and therefore creating c style linkage references.
There are at least 2 ways to fix it:
convert your main.c into a main.cpp and use g++ where you are using gcc now (for your first and 3rd compile and link steps). Then everything will be consistently c++ style references.
Declare within your C++ module (vecAdd.cu) that the external reference should be C style as described here.

Resources