工作整理

目录

    • 1. makefile
    • 2. fopen()
    • 3. fgets()
    • 4. strncmp()
    • 5. strchr()
    • 6.opendir()
    • 7. readdir()
    • 8. dlopen()
    • 9. dlsym()
    • 10. stat()
    • 11. S_ISDIR()
    • 12. popen()
    • 13.awk命令
    • 14. struct ethdr
    • 15. libnet_init() 返回NULL

最近跟老师做项目,在linux下使用C开发,遇到的问题总结。

1. makefile

首先是文件的编译运行,编译使用自己写的makefile文件,可以下载eclipseCDT等ADE用于查看函数声明等,因为一些跳转的快捷键很好用,但是很多配置,以及一些路径总是报错,所以我选择通过命令行以及在代码中添加一些类似如下的输出进行调试,可执行文件通过makefile中指定生成。

printf("file: %s,line:%d\n",__FILE__, __LINE__);

makefile语法

2. fopen()

头文件:#include
fopen()是一个常用的函数,用来以指定的方式打开文件,其原型为:
FILE * fopen(const char * path, const char * mode);
path为包含了路径的文件名,mode为文件打开方式。

【返回值】文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno 中。

注意:一般而言,开文件后会作一些文件读取或写入的动作,若开文件失败,接下来的读写动作也无法顺利进行,所以在fopen()后请作错误判断及处理。

详情

3. fgets()

头文件:# include
fgets() 的原型为:

# include 
char *fgets(char *s, int size, FILE *stream);

其中:s 代表要保存到的内存空间的首地址,可以是字符数组名,也可以是指向字符数组的字符指针变量名。size 代表的是读取字符串的长度。stream 表示从何种流中读取,可以是标准输入流 stdin,也可以是文件流,即从某个文件中读取.。
它的返回值是一个指针,指向字符串中第一个字符的地址。
详情

4. strncmp()

头文件:#include

strncmp() 用来比较两个字符串的前n个字符,区分大小写,其原型为:

    int strncmp ( const char * str1, const char * str2, size_t n );

【参数】str1, str2 为需要比较的两个字符串,n为要比较的字符的数目。
【返回值】若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 若小于s2,则返回小于0的值。
详情

5. strchr()

头文件:#include

strchr() 用来查找某字符在字符串中首次出现的位置,其原型为:

    char * strchr (const char *str, int c);

【参数】str 为要查找的字符串,c 为要查找的字符。

strchr() 将会找出 str 字符串中第一次出现的字符 c 的地址,然后将该地址返回。

注意:字符串 str 的结束标志 NUL 也会被纳入检索范围,所以 str 的组后一个字符也可以被定位。

【返回值】如果找到指定的字符则返回该字符所在地址,否则返回 NULL。
详情

6.opendir()

头文件:#include #include

定义函数:

DIR * opendir(const char * name);

函数说明:opendir()用来打开参数name 指定的目录, 并返回DIR*形态的目录流, 和open()类似, 接下来对目录的读取和搜索都要使用此返回值.

返回值:成功则返回DIR* 型态的目录流, 打开失败则返回NULL.

错误代码:
1、EACCESS 权限不足。
2、EMFILE 已达到进程可同时打开的文件数上限。
3、ENFILE 已达到系统可同时打开的文件数上限。
4、ENOTDIR 参数name 非真正的目录。
5、ENOENT 参数name 指定的目录不存在, 或是参数name 为一空字符串。
6、ENOMEM 核心内存不足。

7. readdir()

头文件:#include #include

定义函数:

struct dirent * readdir(DIR * dir);

函数说明:readdir()返回参数dir 目录流的下个目录进入点。结构dirent 定义如下:

struct dirent
{
    ino_t d_ino; //d_ino 此目录进入点的inode
    ff_t d_off; //d_off 目录文件开头至此目录进入点的位移
    signed short int d_reclen; //d_reclen _name 的长度, 不包含NULL 字符
    unsigned char d_type; //d_type d_name 所指的文件类型 d_name 文件名
    har d_name[256];
};

返回值:成功则返回下个目录进入点. 有错误发生或读取到目录文件尾则返回NULL.

附加说明:EBADF 参数dir 为无效的目录流。

详情

8. dlopen()

头文件 #include
函数原型

void *dlopen(const char *filename, int flag);

注意:在Linux上,使用动态链接的应用程序需要和库libdl.so一起链接,也就是使用选项-ldl。但是,编译时不需要和动态装载的库一起链接。

dlopen()需要两个参数:一个文件名和一个标志。文件名就是一个动态库so文件,标志指明是否立刻计算库的依赖性。如果设置为RTLD_NOW 的话,则立刻计算;如果设置的是 RTLD_LAZY,则在需要的时候才计算。另外,可以指定 RTLD_GLOBAL,它使得那些在以后才加载的库可以获得其中的符号。
当库被装入后,可以把 dlopen() 返回的句柄作为给 dlsym() 的第一个参数,以获得符号在库中的地址。使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。

在dlopen()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。
详情

9. dlsym()

头文件:#include
函数定义:

void*dlsym(void*handle,constchar*symbol)

函数描述:根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。
handle:由dlopen打开动态链接库后返回的指针;
symbol:要求获取的函数或全局变量的名称。
返回值
void* 指向函数的地址,供调用使用。

使用
假设在my.so中定义了一个void mytest()函数,那在使用my.so时先声明一个函数指针:

void(*pMytest)();

接下来先将那个my.so载入:

pHandle=dlopen("my.so",RTLD_LAZY);//详见dlopen函数

然后使用dlsym函数将函数指针 pMytest 指向 mytest() 函数:

pMytest=(void(*)())dlsym(pHandle,"mytest");//可见放在双引号中的mytest不用加括号,即使有参数也不用

(可调用dlerror();返回错误信息,正确返回为空)
最后通过调用函数指针执行mytest函数:

intmain(){
//......
pMytest();
//......
return0;
}

10. stat()

头文件:#include #include

定义函数:

int stat(const char * file_name, struct stat *buf);

函数说明:stat()用来将参数file_name 所指的文件状态, 复制到参数buf 所指的结构中。

下面是struct stat 内各参数的说明:

struct stat
{
    dev_t st_dev; //device 文件的设备编号
    ino_t st_ino; //inode 文件的i-node
    mode_t st_mode; //protection 文件的类型和存取的权限
    nlink_t st_nlink; //number of hard links 连到该文件的硬连接数目, 刚建立的文件值为1.
    uid_t st_uid; //user ID of owner 文件所有者的用户识别码
    gid_t st_gid; //group ID of owner 文件所有者的组识别码
    dev_t st_rdev; //device type 若此文件为装置设备文件, 则为其设备编号
    off_t st_size; //total size, in bytes 文件大小, 以字节计算
    unsigned long st_blksize; //blocksize for filesystem I/O 文件系统的I/O 缓冲区大小.
    unsigned long st_blocks; //number of blocks allocated 占用文件区块的个数, 每一区块大小为512 个字节.
    time_t st_atime; //time of lastaccess 文件最近一次被存取或被执行的时间, 一般只有在用mknod、utime、read、write 与tructate 时改变.
    time_t st_mtime; //time of last modification 文件最后一次被修改的时间, 一般只有在用mknod、utime 和write 时才会改变
    time_t st_ctime; //time of last change i-node 最近一次被更改的时间, 此参数会在文件所有者、组、权限被更改时更新
};

返回值:执行成功则返回0,失败返回-1,错误代码存于errno。

错误代码:
1、ENOENT 参数file_name 指定的文件不存在
2、ENOTDIR 路径中的目录存在但却非真正的目录
3、ELOOP 欲打开的文件有过多符号连接问题, 上限为16 符号连接
4、EFAULT 参数buf 为无效指针, 指向无法存在的内存空间
5、EACCESS 存取文件时被拒绝
6、ENOMEM 核心内存不足
7、ENAMETOOLONG 参数file_name 的路径名称太长

详情

11. S_ISDIR()

功能是判断一个路径是否为目录

12. popen()

头文件:#include

定义函数:

FILE * popen(const char * command, const char * type);

函数说明:popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c 来执行参数command 的指令。

参数type 可使用 "r"代表读取,"w"代表写入。依照此type 值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。

此外,所有使用文件指针(FILE*)操作的函数也都可以使用,除了fclose()以外。

返回值:若成功则返回文件指针, 否则返回NULL, 错误原因存于errno 中.

错误代码:EINVAL 参数type 不合法。
详情

13.awk命令

详情

我遇到的情况是结合popen函数,外面有双引号,所以里面的双引号需要转义符号。

14. struct ethdr

在linux系统中,使用struct ethhdr结构体表示以太网帧的头部。这个struct ethhdr结构体位于linx内核include\linux\if_ether.h中。
结构体原型


<span style="font-family:FangSong_GB2312;font-size:18px;">struct ethhdr
{
    unsigned char h_dest[ETH_ALEN]; //目的MAC地址
     
    unsigned char h_source[ETH_ALEN]; //源MAC地址
     
    __u16 h_proto ; //网络层所使用的协议类型
}__attribute__((packed))  //用于告诉编译器不要对这个结构体中的缝隙部分进行填充操作;

详情

15. libnet_init() 返回NULL

inux下使用libnet时,libnet_init()总是返回NULL
方法:

libnet_init()需要root权限,
把权限改成root就行了

这条很实用,项目运行在root用户下即可。

你可能感兴趣的:(日常)