美文网首页
Linux-C起步

Linux-C起步

作者: hutou | 来源:发表于2018-01-25 10:14 被阅读17次

    名称解释

    1. ANSI C
      C语言标准,为各种操作系统上的C程序提供可移植性的保证
    2. POSIX标准
      定义了兼容操作系统的C语言系统接口以及工具标准
    3. 库函数
      库函数完成常见的特定功能,被应用程序调用
    4. 系统调用
      系统调用函数与操作系统相关,不同的操作系统使用的系统调用可能不同。库函数中也可以使用系统调用

    第一个程序

    写一个程序first.c

    #include <stdio.h>
    
    int main(int argc,char **argv)
    {
      printf("this is first proram.\n");
      return 0;
    }
    

    使用gcc进行编译,链接

    $ gcc first.c
    

    运行一下看结果

    $ ./a.out
    

    调用函数

    写一个阶乘的函数factorial.c

    #include <stdio.h>
    #include <stdlib.h>
    
    int factorial(int n)
    {
      if(n <= 1) return 1;
      else
        return factorial (n-1) * n;
    }
    

    写一个调用文件second.c

    #include <stdio.h>
    #include <stdlib.h>
    
    int factorial(int n);
    
    int main(int argc, char **argv)
    {
      int n;
      if(argc < 2){
        printf("Usage: %s \n", argv[0]);
        return -1;
      }else{
        n = atoi(argv[1]);
        printf("Factorial of %d is %d . \n",n,factorial(n));
        return 0;
      }
    }
    

    编译和调用方法

    $ gcc -c factorial.c
    $ gcc -c second.c
    $ gcc -o second factorial.o second.o
    $ ./second  6
    

    Make工具的使用

    刚才我们看到了,如果我们的程序有多个文件,我们需要编译,链接才能正常调用程序。这个过程是很繁琐的,我们可以使用make工具来解决这个问题。
    make工具会调用makefile文件,我们先写一个makefile看看
    Makefile

    second : second.o factorial.o
            gcc -o second second.o factorial.o
    second.o : second.c
            gcc -c second.c
    factorial.o : factorial.c
            gcc -c factorial.c
    clean :
            rm -f *.o
            rm -f second
    

    如果发现make有如下错误:

    Makefile:2: *** 遗漏分隔符 。 停止。
    

    可能是执行文件开头使用了空格,应该使用TAB。

    Makefile中的常用变量
    $@--目标文件
    $^--所有依赖的文件
    @<--第一个依赖文件

    main: main.o mytool1.o mytool2.o
            cc -o $@ $^
    main.o: main.c mytool1.h mytool2.h
            cc -c $<
    mytool1.o: mytool1.c mytool1.h
            cc -c $<
    mytool2.o: mytool2.c mytool2.h
            cc -c $<
    

    库文件的使用

    上面的例子中我们使用了printf函数,这个函数的实现是在库文件中。我们连接自己的应用程序的时候,编译器会查找对应函数的连接位置,运行时在当前系统内存空间中查找该库函数在对应库文件中的位置。
    Linux系统下有两种库文件:

    1. 静态库:.a为后缀,应用程序从静态库中复制函数到二进制文件中
    2. 共享库:.so为后缀,应用程序运行时将函数代码从共享库文件中读出,从而间接引用。

    系统库的路径:

    # 系统必备共享库
    /lib
    # 标准共享库和静态库
    /usr/lib
    # 本地函数库
    /usr/local/lib
    

    库文件的搜索路径为:

    1. 环境变量:LD_LIBRARY_PATH 所指定的位置
    2. 搜索动态加载器在/etc 目录下的缓存文件 /etc/ld.so.cache

    在进行cc编译的时候,会自动链接一些常用的库,这就是为什么printf不需要指定链接库的原因。如果我们需要指定库的路径可以使用如下方法:

    cc -o temp temp.c -L/home/hutou/myLib
    

    系统缺省库位置:/lib,/usr/lib,/usr/local/lib

    静态库的使用

    1. 创建静态库:主要使用ar命令
      创建hello.c,hello.h 文件
    #ifndef _libhello_H_
    #define _libhello_H_
    void hello(void);
    
    #endif
    
    #include <stdio.h>
    #include "hello.h"
    
    void hello(void){
            printf("this is a static lib.\n");
    }
    

    编译生成静态库hello.a

    $ gcc -c hello.c
    $ ar rc hello.a hello.o
    
    1. 使用静态库
      使用静态库需要两个文件:头文件,静态库文件
      默认库文件如果不在库搜索路径中,需要将此库文件拷贝到当前目录,或者在编译时指定库文件路径
      书写一个调用静态库的文件 libuse.c
    #include <stdio.h>
    #include "hello.h"
    
    int main(int argc, char **argv){
            hello();
            return 0;
    }
    

    编译链接

    $ gcc -o useHello libuse.c hello.a 
    

    共享库的使用

    共享库的创建基本上与静态库相同,主要的差别体现在编译上

    1. 使用gcc和参数-fPIC将源代码编译成.o的目标代码
    2. 使用-shared来创建共享库

    下面我们使用上面的hello.c,编译成共享库

    # 生成.o的目标文件
    gcc -fPIC -c hello.c
    # 编译共享库,指定共享库名称和版本,-lc表示引用c库
     gcc -shared  -o libhello.so.1.0 hello.o -lc
    # 创建软连接
    ln -sf libhello.so.1.0 libhello.so
    

    下面我们看看怎么使用共享库

    # 编译程序,生成目标文件
    gcc -c libuse.c -o libuse.o
    # 连接程序,-L 表示查找库的路径
    gcc -o useDynHello libuse.o -L ./ -lhello
    # 通过ldd命令查看引用的动态库
    ldd useDynHello
    # 调用程序,需要指定共享库的位置
    LD_LIBRARY_PATH=$(pwd) ./useDynHello
    

    说明一下,还记得我们说过的库文件的搜索路径。我们在链接程序的时候,指定了 -L 的路径,如果将我们的共享库放置在可以搜索到的路径下,则不用指定此参数。

    进程

    程序:包含可执行代码的文件,是一个静态文件。
    进程:一个开始执行但是还没有结束的程序实例。
    程序被系统调入内存,系统给程序分配一定的资源,让程序变成进程,为了区分进程,系统会给每一个进程分配一个ID号。进程有新建,运行,阻塞,就绪,完成五个状态。

    1. 获得进程ID号
    #include <unist.h>
    pid_t getpid(void);  //  获得进程的ID
    pid_t getppid(void);  //  获得父进程的ID
    

    演示用程序

    #include <unistd.h>
    #include <stdio.h>
    int main(int argc,char *argv){
            printf("process id = %d\n",getpid());
            printf("process parent id = %d\n", getppid());
    }
    
    1. 运行中出现:段错误(吐核)
      使用如下的命令进行调试(pid是运行的程序)
    strace ./pid
    
    1. 进程的所有者和执行者
    #include <stdio.h>
    #include <sys/types.h>
    int main(int argc, char const *argv[])
    {
        printf("这是程序的运行者%d\n", getuid());
        printf("这是程序的所有者%d\n", geteuid());
        printf("这是组ID =%s\n", getgid());
        printf("这是组EID =%s\n", getegid());
        return 0;
    }
    
    1. 登录用信息
    #include <stdio.h>
    #include <pwd.h>
    int main(int argc, char const *argv[])
    {
            struct passwd* my_info;
            my_info = getpwuid(getuid());
    
            if(my_info)
            {
                    printf("我的登录名:%s\n", my_info->pw_name);
                    printf("我的密码:%s\n", my_info->pw_passwd);
                    printf("我的ID= %ld\n", my_info->pw_uid);
                    printf("我的组ID= %ld\n", my_info->pw_gid );
                    printf("我的真实名称:%s\n", my_info->pw_gecos);
                    printf("我的Home目录:%s\n", my_info->pw_dir);
                    printf("我的Sheel:%s\n", my_info->pw_shell);
            }
            return 0;
    }
    

    相关文章

      网友评论

          本文标题:Linux-C起步

          本文链接:https://www.haomeiwen.com/subject/wkucpttx.html