In depth understanding of common compile related errors in C

  • 2020-04-01 23:38:52
  • OfStack

1. / usr/lib/GCC/i686 - - the gnu/Linux 4.6 /.. /.. /.. / i386 - - the gnu/Linux crt1. O: In function ` _start ':
(.text+0x18): undefined reference to 'main'
Collect2: ld returns 1
Reason: no main function in source file
2. To get compile options -I and -l
PKG - config lib
Gear: pkg-config --cflags --libs dbus-1 glib-2.0 dbus-glib-1
C 'pkg-config --cflags --libs dbus-1 glib-2.0 dbus-glib-1
3. How to get pkg-config to find its own library
In the library, there is a file called libxxx.pc.in, which defines where the header files it provides are, what they are, how the libraries are linked, and where the libraries are located. This of course is all information after the library is installed into the system.

prefix=@PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: library name
Description: description goes here
Requires: glib-2.0 gobject-2.0
Version: 0.1
Libs: -L${libdir} -llibrary_name
Cflags: -I${includedir}/some_sub_dir

This file defines all the information for the library after installation, which is read by pkg-config.
4. Forward declaration and incomplete type
This error is usually due to the use of a specific type, but this type (at the time of use) is only declared, not defined. For example, a header file might have the following declaration:

#ifndef __POINT_H
#define__POINT_H
typedef struct _Point Point;
#endif

If the file contains this header file, you can use Point to declare:
      1). As the formal parameter when declaring the function, void print_point(Point p), note that is when declaring the function, not the definition of the function
      2). Declaration pointer: Point *p;
But you can't use Point to define variables,
      1). For example, define variables, Point p;
      Void print_point(Point p) {... }
      3). Or when applying inner space for its pointer, Point * Point = (Point *) calloc(1, sizeof(Point));
A compilation error for incomplete type is reported. Because the memory size of the Notification and the specific form of definition are required at this time, the header file does not give the specific definition, so the compiler does not know the memory required for this type, so it will compile incorrectly.
This is also true in C++, where, for efficiency, a Forward declaration is made, in which a class is not specified before it is used, but an undefined class is declared:
The class Point;
Point a;
When using a Foward declaration, you can only use it to declare, not to specify the type.
Therefore, if you want to use a specific type, the header file it contains must have a specific definition of the type:

#ifndef __POINT_H
#define __POINT_H
typedef struct _Point Point;
struct _Point {
      int x;
      int y;
};
#endif
#include "point.h"
Point *n = (Point *) calloc(1, sizeof(Point));
n->x = 1;
n->y = 2;
....

The reason is also simple, when you need a type to declare a variable, you don't need to allocate memory, you don't need to operate on it, and you don't need to know the specific type definition. But when you use it, when you want to allocate memory, you have to understand how the type is defined, otherwise you can't do it, so you have to know exactly what the type is.
In fact, the purpose of declaring only the type in the header file is to hide the information, that is, to not let the caller know what the specific definition of the type is, so you need to define the type as you do in Java/C++.
      1) declare the type as pointer type:
      Typedef struct Point * Point;
      Otherwise it's still possible for the caller to define.
      2) that is, all methods that operate on this type are encapsulated in the corresponding source file of the header file, so that there is no need for the outside world to understand how the type is defined. When it wants to operate, it simply calls the encapsulated method.
Typical examples:
The header file point. H:

#ifndef __POINT_H
#define __POINT_H
typedef struct _Point *Point;
Point make_point();
void print_point(Point point);
void destroy_point(Point p);
#endif

Implement source file: point.c

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "point.h"
struct _Point {
    int x;
    int y;
};
Point make_point() {
    Point point = (Point) calloc(1, sizeof(struct _Point));
    point->x = 0;
    point->y = 0;
    return point;
}
void print_point(Point point) {
    printf("point %d, %dn", point->x, point->y);
}
void destroy_point(Point p) {
    if (p == NULL) {
         printf("warning, destroying NULL object");
         return;
    }
    free(p);
}


Related articles: