• C语言拾遗-机制


    Vim一些技巧

    # 以十六进制形式查看,二进制代码文件
    %!xxd		# % 代表当前编辑的文件, xxd以十六进制显示该文件, xxd -r还原为二进制。
    set nowrap	# 不换行
    
    w		# 保存
    wq		# 保存退出
    q!		# 强制不保存退出
    The ! qualifier tells Vim to force the operation. 
    For example
    if the file was read-only you would use :w! to write it anyway. 
    If the file was modified and you wanted to quit without saving, you would use :q!. 
    :wq! just means force write and quit in one command.
    
    # 在Vim中可以用添加前缀!的方式执行外部命令, 例如 !ls, 其结果将被在底部输出
    !ls
    !gcc %				# % 表示当前文件
    !./a.out
    
    vim中:h是向左,l是向右,j是向下,k是向上
    
    vs [filename]	# 开启左右分屏
    sp [filename]	# 开启上下分屏
    先按ctrl + w, 松开之后按w 	# 左右切换分屏
    先按ctrl + w, 松开之后按h	# 切换到左边的分屏
    先按ctrl + w, 松开之后按l	# 切换到右边的分屏
    
    改变当前分屏的位置
    先按ctrl+w,之后按r 			# 切换分屏位置
    先按ctrl+w,之后shift+h		# 将当前分屏移到最左边
    先按ctrl+w,之后shift+l		# 将当前分屏移到最右边
    
    改变当前分屏的宽度
    先按ctrl+w,之后输入数字N, 之后shift+>		# 将当前分屏的宽度加N
    先按ctrl+w,之后shift+>		# 将当前分屏的宽度加一
    先按ctrl+w,之后shift+<		# 将当前分屏的宽度减一
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    Vim编辑器分屏操作
    Vim 分屏操作
    wc命令查看文件的行数,字数,字节数

    print newline, word, and byte counts for each file
    
    # 0行, 1个单词, 11个字节/字符(因为一个英文字符对应一个字节)
    [root@localhost c]# ./helo_lin | wc
          0       1      11
    
    • 1
    • 2
    • 3
    • 4
    • 5

    file命令查看文件信息

    file a.out	# 查看文件信息
    a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), 
    for GNU/Linux 2.6.32, BuildID[sha1]=6e5966737b911cc5abc2cff490aa669416c1298f, not stripped
    
    • 1
    • 2
    • 3

    反汇编:将机器代码转换为汇编代码

    # 把目标代码转为汇编代码
    [root@localhost c]# objdump -d  hello.o
    
    hello.o:     文件格式 elf64-x86-64
    Disassembly of section .text:
    
    0000000000000000 <main>:
       0:   55                      push   %rbp
       1:   48 89 e5                mov    %rsp,%rbp
       4:   bf 00 00 00 00          mov    $0x0,%edi
       9:   b8 00 00 00 00          mov    $0x0,%eax
       e:   e8 00 00 00 00          callq  13 <main+0x13>
      13:   5d                      pop    %rbp
      14:   c3                      retq 
    
    # 查看版本
      -V
    # 从二进制文件中反汇编那些特定指令机器码的section.
      -d, --disassemble        Display assembler contents of executable sections
    # 与 -d 类似, 但反汇编所有section. 
      -D, --disassemble-all    Display assembler contents of all sections
    # 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。
      -S, --source             Intermix source code with disassembly(既有源代码也有汇编)
    # 显示档案库的成员信息,类似ls -l将lib*.a的信息列出。 
      -a 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    程序内存分区

    一个程序本质上都是由 bss段、data段、text段三个组成的。
    # bss段, data段 属于静态内存分配 
    bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域
    数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域
    # text
    代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域
    # heap
    堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。
    当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)
    当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)# stack
    栈又称堆栈,是用户存放程序临时创建的局部变量
    也就是函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)
    除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中
    
    一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。
    比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。
    text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载
    而bss段不在可执行文件中,由系统初始化。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    (深入理解计算机系统) bss段,data段、text段、堆(heap)和栈(stack)
    objdump命令
    #include实际上做的事情就是:把要引入的文件的内容插入到这里
    #include<>只会从系统类库目录里查找头文件,在Linux下是
    /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
    /usr/local/include
    /usr/include
    找不到就会报错,所以引用系统头文件,使用<>
    #include""查找位置是当前源文件所在目录
    1、#include<>一般用于包含系统头文件,诸如stdlib.h、stdio.h、iostream等
    2、#include""一般用于包含自定义头文件,比如我们自定义的test.h、declare.h等
    include头文件时尖括号<>与双引号""的区别
    GCC编译C语言代码的过程

    gcc --verbose hello.c
    
    # cc1 将.c源代码文件 编译成一个.s 汇编文件
    COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
    /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 -quiet -v hello.c -quiet -dumpbase hello.c 
    -mtune=generic -march=x86-64 -auxbase hello -version -o /tmp/ccWC7Yvb.s
    
    # as 将.s汇编文件 生成 .o目标文件
    COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
    as -v --64 -o /tmp/ccQoZ2kO.o /tmp/ccWC7Yvb.s
    
    # collect2 将.o文件和系统库的.o文件,库文件连接起来,生成可执行文件
    # collect2是ld链接器的一个封装
    COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
    /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu 
    -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 
    /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o 
    /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o 
    /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o 
    -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 
    -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 
    -L/lib/../lib64 -L/usr/lib/../lib64 
    -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. 
    /tmp/ccQoZ2kO.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s 
    --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o 
    /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
    # crt1.o、crti.o、crtbegin.o、crtend.o、crtn.o是gcc加入的系统标准启动文件,对于一般应用程序,这些启动是必需的
    # -lc:链接libc库文件,其中libc库文件中就实现了printf等函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    collect2主要实现了两个额外的功能,都是为C++程序准备的。其一是生成代码调用全局静态对象的构造函数和析构函数;其二是支持Cfront方式生成模板代码。
    collect2调用ld生成一个执行程序,然后调用nm程序,根据命名规则,查找所有的调用全局静态对象构造函数和析构函数的函数,并将这些函数保存为一张表,再生成一段代码遍历每个表项,调用对应的函数。所有这些信息被保存为一个C程序,然后编译、汇编为目标文件,在链接时作为第一个目标文件传给linker,做第二次链接。此功能实现在gcc/collect2.c文件内。通过在config.gcc文件里查找use_collect2=yes来确定哪些系统使用了该功能,PC上默认是关闭的。
    gcc编译链接原理及使用
    预处理功能:
    (1)文件包含:把包含的.h文件找到并展开到#include所在处。
    (2)条件编译:预处理器根据#if和#ifdef等编译命令及其后的条件,把源程序中的某些部分包含进来或排除在外,通常把排除在外的语句转换成空行。
    (3)宏展开:预处理器将源程序中对宏的引用展开成相应的宏定义,只是纯粹的文本替换,没有任何计算。

    #define MAX 10
    #define MAX(a,b) ((a) > (b) ? (a) : (b))
    #define area(x) ((x)*(x))
    define的单行定义
        #define A(x,y) x##y	// A(123,456)结果是123456表示连接
        #define B(x) #@x	// 给x加上单引号
        #define C(x) #x		// 给x加双引号
    define的多行定义
        #define MACRO(arg1,arg2) do {  \
        test1; \
        test2; \
        }while(0)
    // 在每一行的末尾要加上\,切记!
    // 定义一个宏使用#define, 取消一个宏定义使用#undef
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    C语言宏#define(精通详解)
    C语言宏嵌套的展开规则
    C语言中define的全部使用方法总结
    centos创建新用户

    [root@localhost ~]# adduser hhx			# 创建用户
    [root@localhost ~]# passwd hhx			# 为hhx用户设置密码
    
    • 1
    • 2

    centos7中添加新用户并授权

  • 相关阅读:
    微信小程序如何获取地理位置
    大华同轴电缆低时延监控方案300ms
    C和指针 第12章 使用结构和指针 12.3 双链表
    Linux期末总复习( 详解 )
    什么是数字孪生智慧城市应用场景
    研究生英语复习(一)
    英伟达的AI霸主地位会持久吗?
    Purple Pi OH(Debian/Ubuntu)使用python控制gpio
    计算机竞赛 机器视觉opencv答题卡识别系统
    Redis使用基础教程
  • 原文地址:https://blog.csdn.net/qq_53318060/article/details/126308225