linux c语言排错,深入理解C语言中编译相关的常见错误

1. /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':

(.text+0x18): undefined reference to `main'

collect2: ld 返回 1

Reason: no main function in source file

2. to get compile options -I and -lpkg-config lib

e.g: pkg-config --cflags --libs dbus-1 glib-2.0 dbus-glib-1

gcc -o send-sms send-sms.c `pkg-config --cflags --libs dbus-1 glib-2.0 dbus-glib-1`

3. 如何让pkg-config找到自己写的库在库中有一个文件libxxx.pc.in,其中会定义它所提供的头文件在哪里,有哪些,其库链接方式是怎么样,库在哪里,当然这都是库安装到系统以后的信息,换句话说,可能对于编译环境是无意义的。

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

这个文件定义了安装后此库的所有信息,而pkg-config就会读取此信息。

4. forward declaration and incomplete type出现这种错误的时候通常是由于具体使用了某种类型,但此类型(到使用的时候)还仅有声明,未有定义。比如说,某个头文件有如下声明:

#ifndef __POINT_H

#define__POINT_H

typedef struct _Point Point;

#endif

如果包含了此头文件的文件,可以使用Point去声明:    1).如声明函数时的形式参数,void print_point(Point p),注意是声明函数时,而不是定义函数

2). 声明指针:Point *p;

但是不能使用Point去定义变量,

1). 如定义变量,Point p;

2). 定义函数时的形参,void print_point(Point p) { ... }

3) .或者为其指针申请内在空间时,Point *point = (Point *) calloc(1, sizeof(Point));

会报出incomplete type的编译错误。因为这个时候需要Notification所占的内存大小和具体的定义形式,但是头文件中并没有给出具体的定义,所以编译器不知道此类型所需要的内存,所以会编译出错。

C++中也是如此,为了效率会Forward declaration,也即在使用某个类前,不具体指定其类,而是声明一个没有定义的类:

class Point;

Point a;

使用Foward declaration时,也只能用其去声明,而不能具体使用此类型。

所以,如果要具体使用某个类型时,其所包含的头文件中必须要有类型的具体定义:

#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;

....

其实原因也很简单,当令需要某个类型来声明变量时,不需分配内存,不需要对其进行操作,自然就不用了解其具体的类型定义。但当你使用时,要分配内存时,就必须要了解类型是怎么定义的,否则这些操作无法完成,这自然就需要知道类型的具体定义。

其实,在头文件中仅声明类型的目的是为了信息隐藏,也就是不让调用者知道这个类型具体的定义是什么样子的,那么就需要像Java/C++中那样去定义这个类型,

1) 把类型声明为指针类型:

typedef struct Point *Point;

否则调用者还是有可能去定义。

2) 也即在头文件的对应源文件中封装操作此类型的所有方法,这样外界就没有必要去了解类型是如何定义的了。它想操作时,仅需要调用封装的方法即可。典型的实例:

头文件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

实现源文件:point.c

#include

#include

#include

#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, %d\n", point->x, point->y);

}

void destroy_point(Point p) {

if (p == NULL) {

printf("warning, destroying NULL object");

return;

}

free(p);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值