浅显易懂的GCC使用教程——初级篇

2023-11-08

浅显易懂的GCC使用教程——初级篇

  2018-12-17天气暖,属于冬日里出太阳。最近在学习使用gvim,想着抛弃对IDE的依赖同时也是想了解编译的过程,但除了学习gvim繁多的指令外还得先学习使用gcc编译程序。这篇文章将会用浅显易懂的方式记录下gcc的基本使用,同时也不忘扩展探究。

——Author:Calm

  • 什么是GCC,它能干什么?

  • GCC、gcc、g++三者有何关系?

  • 开始开发前该做什么准备?

  • gcc常用指令讲解?

  • 什么是gcc,它能干什么?

      GCC(GNU Compiler Collection)即GNU编译器套件,属于一种编程语言编译器,其原名为GCC(GNU C Compiler)即GNU c语言编译器,虽然缩写一样但是功能上区别很大。GCC的初衷是为GNU操作系统专门编写的一款编译器,原本的GNU是专用于编译C代码,现如今已扩展为可以编译C、C++、Java、Objective-C等多种编程语言的编译器集合了。这篇文章主要介绍gcc或g++的使用。

  • GCC、gcc、g++三者有何关系?

      gcc(GUN C Compiler)是GCC中的c编译器,而g++(GUN C++ Compiler)是GCC中的c++编译器。
      gcc和g++两者都可以编译c和cpp文件,但存在差异。gcc在编译cpp时语法按照c来编译但默认不能链接到c++的库(gcc默认链接c库,g++默认链接c++库)。g++编译.c和.cpp文件都统一按cpp的语法规则来编译。所以一般编译c用gcc,编译c++用g++。后文有时间会继续深入探讨区别。

  • 开始开发前该做什么准备?

    • 软件安装教程:
        直接去官网上下载MinGW的包管理器(下载链接:https://osdn.net/projects/mingw/releases/

        下载好后安装包管理器并运行它,可以看到如下界面:

      在这里插入图片描述

        左侧选择“Basic Setup”选项,右侧勾选(点击“Mark for Installation”)需要安装的组件“mingw32-gcc-g++”。假设你也需要使用MinGW编译Fortran、Object-C、Ada语言的话也可以勾上相应的选项。选择好后点击左上角的Installation菜单中的Apply changes选项即开始在线下载安装相关组件。

        安装好后最好配置下环境变量,把MinGw的bin目录加入到环境变量的path中,这样dos在任意目录下都可以调用bin目录下的可执行文件,其他一些软件也能找到gcc的位置。cmd中输入gcc -v查看版本号。

      alt test

  • gcc常用指令讲解?

      用gcc在Windows上编译*.c文件并非直接生成*.exe文件(Linux上为*.out),中间还经历了预处理、编译和汇编几个过程,好在gcc提供了生成中间文件的指令,虽然平时开发的时候很少关注编译过程中生成的这些*.i和*.s文件,但对其有一定的了解总归是好的。

    在这里插入图片描述

    • 【指令】 gcc
        使用gcc指令编译*.c文件可以生成*exe可执行文件。下面我们用一段简单的c代码来讲解,Demo.c内源码如下:

      
      	#include<stdio.h>
      	
      	int main(void)
      	{
      	    printf("nihao\n");
      	
      	    return 0;
      	}
      
      

        打开cmd,需要注意的是cmd默认路径一般是c盘,而Demo.c文件可能并不在cmd的默认路径下,我们需要使用dos指令cd到Demo.c所在目录下才能对文件进行操作,示例:

      alt test

        对Demo.c文件执行gcc指令后会在该目录下生成可执行文件a.exe,由于没有制定exe的文件名所以默认为a.exe。

      alt text

        当然也不一定要cd进Demo.c的目录,使用gcc指令时给出Demo.c的绝对路径也可以成功编译,命令如下:

      gcc E:\WorkSpace\Test_gcc\Demo.c

    • 【指令】 -o
        指令-o(小写)用来指定生成的文件名。

      alt text

      结果如下:

      alt text

        生成的文件不一定要在.c所在目录,可以给出路径指定。

      gcc Demo.c -o ..\Demo.exe

        该指令指定将exe生成到上一级目录。

        生成exe后我们试者执行一下看看结果。

      alt text

    • 【指令】 -E(预处理(Preprocessing))
        指令 -E(大写)将执行预处理操作也即生成*.i文件,gcc编译器将对#开头的指令进行解析。我们修改Demo.c中的代码为如下:

      
      	#include <stdio.h>
      	#include <stdlib.h>
      	#include "Test.h"
      	
      	int main()
      	{
      	    int a = N;                      //宏常量
      	    int b = 2;
      	    int c = 0;
      	    
      	    c = a + b;
      	    printf("%d\n", c);
      	    
      	    CODE                            //宏替换代码段
      
      		DoNothing();
      	
      	    system("pause");
      	    return 0;
      	}
      
      

      在Demo.c同目录下编辑Test.h文件,源码如下:

      
      	#define N 1
      	
      	#define     CODE      if(c > 2)                              \
      	                                {                            \
      	                                    printf("c > 2\n");       \
      	                                }
      	
      	void DoNothing(void);           //函数声明(该函数未被调用)
      
      

      在Demo.c同目录下编辑Test.c文件,源码如下:

      
      	#include"Test.h"
      	
      	void DoNothing(void)
      	{
      	    ;
      	
      	    return ;
      	}
      
      

        从源码可知Demo.c中在预处理阶段需要把调用的头文件包含进来,替换宏常量和宏代码段。我们执行指令gcc -E Demo.c -o Demo.i并看看Demo.i文件中的代码。

      Demo.i文件内容:

      alt text

        -E 指令使gcc执行预处理,预处理时对#类指令进行处理(包含头文件、替换宏常量和宏代码段等操作),也就不难理解为何Demo.i文件会很大了(38KB),整个工程最后被揉合成一个大文件。预处理把注释都去掉了,所以反编译回来的代码是没有注释的!因为注释早就被去掉了。另外可以一提的是使用指令gcc -E Demo.c不指定输出的文件名时内容将会直接输出到Dos框中,而不会产生文件。

        我们知道c语言出现语法错误时编译器将会报错,但检查语法错误是在预处理、编译、汇编、链接、生成可执行文件中的哪个阶段执行的呢?为了方便我们编辑Demo2.c代码,有意使源码代码由于错误测试预处理阶段是否会报语法错误。

      
      	#include<stdio.h>
      	
      	int main(void)
      	{
      	    aabbccdd          //此处有语法错误
      	
      	    return 0;
      	}
      
      

        对Demo2.c执行预处理操作gcc -E Demo2.c

      alt test

        由此可知预处理阶段不检查语法错误。

    • 【指令】 -S(编译(Compiling))
        执行-S(大写)指令将*.i文件中源码转化为汇编代码*.s文件。我们执行指令gcc -S Demo.i -o Demo.s,在当前目录下将生成Demo.s文件,用记事本打开会发现c源码已经被编译器转化为汇编代码。

      在这里插入图片描述

        如果使用指令gcc -S Demo.i即不指定输出文件名,默认也将会在当前目录下产生文件Demo.s。

        关于前面含有语法错误的Demo2.c我们在编译阶段再试一次,看看是否能检查出语法错误。

      alt text

        对语法的检查是再编译阶段进行的。

    • 【指令】 -c(汇编(Assembling))
        执行-c(小写)指令将*.s文件中的汇编源码转化未机器能执行的二进制机器码,生成文件*.o。执行指令gcc -c Demo.s -o Demo.o。生成的Demo.o为二进制文件,用记事本打开就是一堆乱码,我这里就不贴图出来了。

    • 【指令】 gcc *.o(链接(Linking))
        经过汇编处理后生成的二进制文件Demo.o虽然已经机器码,但仍然无法运行因为少了链接操作。链接操作可执行指令gcc Demo.o -o Demo.exe

      alt text

        对Demo.o执行链接操作出现报错,提示找不到函数DoNothing的定义。预处理阶段值时将头文件包含进Demo.i文件中,也即Demo.i中含有函数的声明部分,所以编译阶段只检查函数的声明和调用处是否符合函数原型,并未去检查其他*.c文件中的函数定义。
        链接阶段就是要把函数库中的函数定义给关联进来,找不到函数定义当然会报错。那么问题来了,我们调用的标准库函数printf为何不报错?其实库函数也不例外,在链接阶段需要关联到函数定义,它的声明部分在标准库函数头文件stdio.h中已给出,而实现部分在某个标准库中封装好了,不同的系统下还会有差异。gcc在链接时默认是包含标准库的库文件路径的,所以它能找到printf函数的定义而不会报错。而DoNothing函数是我们用户自己编写,并未封装成库的形式gcc当然找不到它的定义。倘若把Demo.c中的DoNothing函数调用去掉可以成功执行链接操作吗?当然可以!

        为了让Demo.o能成功的生成可执行文件Demo.exe,我们可以将Test.c封装成静态库供其调用,这样就有函数定义了。执行指令gcc -c Test.c -o Test.o生成Test.o二进制文件。这里并不是不用对Test.c执行预处理和编译操作,而是编译器帮我们做了。接着将Test.o生成静态库文件libTest.a,然后再次尝试对Demo.o执行链接操作。

      alt text

        可以看到这次编译器没有报错且成功生成了Demo.exe,执行结果也与预期一直。
        关于生成静态库和动态库的gcc指令以及更多其他指令,静态库和动态库的区别和作用,等有时间了继续写个中级篇来讲解吧,一篇文章写得太长大家看了也会枯燥,我写着也需要休息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

浅显易懂的GCC使用教程——初级篇 的相关文章

  • 编译器 libstdc++ 版本与系统版本

    我试图了解 g 如何选择它链接的 libstdc 版本 以及当库的 系统 版本不同时它意味着什么 我正在使用 gcc g 4 1 2 根据ABI 指南 http gcc gnu org onlinedocs libstdc manual a
  • 使用 AVX 内在函数代替 SSE 并不能提高速度 - 为什么?

    我已经使用 Intel 的 SSE 内在函数相当长一段时间了 并取得了良好的性能提升 因此 我希望 AVX 内在函数能够进一步加速我的程序 不幸的是 直到现在情况并非如此 可能我犯了一个愚蠢的错误 所以如果有人能帮助我 我将非常感激 我使用
  • C 中类似函数的宏定义

    我想定义一个像 MACRO 这样的函数 IE define foo x if x gt 32 x else 2 x endif 那是 if x gt 32 then foo x present x else foo x present 2
  • 软件预取手动指令合理的场景

    我读过有关 x86 和 x86 64 Intel 的内容gcc提供特殊的预取指令 include
  • 用更有意义的文本替换 GCC 输出中的 a-hats [重复]

    这个问题在这里已经有答案了 可能的重复 为什么 gcc 的所有错误消息中都有 https stackoverflow com questions 547071 why does gcc have a in all its error mes
  • typeof() 表达式内的副作用

    在 GNUC C 中 您可以使用typeof expression 并且使用内部带有副作用的表达式是合法的 例如 您可以使用以下 C 代码 int x 0 typeof x y 在这种情况下 副作用被忽略 并且 x 之后仍然为零 这是有道理
  • GCC 对潜在有效的代码抛出 init-list-lifetime 警告?

    我在 Debian不稳定的GCC 9 3 0上运行 我从事的一个项目最近发生了变化 引入了类似于下面的代码 include
  • 这种对有效类型规则的使用是否严格遵守?

    C99和C11中的有效类型规则规定 没有声明类型的存储可以用任何类型写入 并且存储非字符类型的值将相应地设置存储的有效类型 抛开 INT MAX 可能小于 123456789 的事实不谈 以下代码对有效类型规则的使用是否严格符合 inclu
  • 公共基类打破了元组的空基类优化

    gcc 4 7 1 对元组进行空基类优化 我认为这是一个非常有用的功能 然而 这似乎有一个意想不到的限制 include
  • 什么定义了类型的大小?

    ISO C 标准规定 sizeof char lt sizeof short lt sizeof int lt sizeof long 我在 BIT Linux mint 19 1 上使用 GCC 8 大小为long int is 8 我正
  • 'goto *foo' 其中 foo 不是指针。这是什么?

    我正在玩标签作为值 https gcc gnu org onlinedocs gcc Labels as Values html并最终得到这段代码 int foo 0 goto foo 我的 C C 经验告诉我 foo means dere
  • 在 C++17 中使用 成员的链接错误

    我在 Ubuntu 16 04 上使用 gcc 7 2 并且需要使用 C 17 中的新文件系统库 尽管确实有一个名为experimental filesystem的库 但我无法使用它的任何成员 例如 当我尝试编译此文件时 include
  • 包括带有大量全局变量的 C 头文件

    我有一个包含 100 多个全局变量的包含文件 它正在库中使用 但我链接库的一些程序也需要访问全局变量 它的构建方式 In one library c file define Extern In the programs that use t
  • 编译时未定义对“WinMain@16”的引用

    我刚刚安装视觉工作室代码当出现这个问题时 我正在尝试运行我的代码 编译时未定义对 WinMain 16 的引用 我在网上搜索了相关答案 但没有找到有效的答案 这里有一个更详细的output在控制台中 cd f g testing cpp o
  • 如何在 GCC 5 中处理双 ABI?

    我尝试了解如何克服 GCC 5 中引入的双重 ABI 的问题 但是 我没能做到 这是一个重现错误的非常简单的示例 我使用的GCC版本是5 2 如您所见 我的主要函数 在 main cpp 文件中 非常简单 main cpp include
  • clang 是否提供类似于 GCC 6.x 的函数多版本控制 (target_clones) 的功能?

    我读了这篇 LWN 文章 https lwn net Articles 691932 饶有兴趣 执行摘要 GCC 6 x 支持所谓的函数多版本控制 它可以构建同一函数的多个版本 并针对不同的指令集进行优化 假设您有一台支持 AVX2 的机器
  • 为什么 gcc 链接时没有 lpthread 标志?

    我当时正在做一个业余爱好项目 其中互斥体的行为很神秘 我将其归结为这个显然应该陷入僵局的测试用例 include
  • C++11 Geany 设置

    我正在学习 C 我需要在 Geany 中为 C 11 正确设置编译和构建命令 我以为我的理解是正确的 但是当使用时auto 我收到以下错误 warning auto will change meaning in C 0x please re
  • GCC 的“-Wl,option”和“-Xlinker option”语法之间有区别吗?

    我一直在查看一些配置文件 并且看到它们都被使用 尽管在不同的体系结构上 如果您在 Linux 机器上使用 GCC 将选项传递给链接器的两种语法之间有区别吗 据我所知 阅读 GCC 手册时 他们的解释几乎相同 From man gcc Xli
  • Clang 3.2 构建在构建 gcc 4.7 后损坏

    所以我知道 Clang 大多数时候 依赖于 Gnu 的 libstdc 3 但是在构建 gcc 4 7 0 因为太棒了 之后 我似乎遇到了问题 clang 的所有路径都是错误的 我是否需要清理我的构建目录并从头开始使用 clang 特别是它

随机推荐

  • 美图赶上了AIGC浪潮?

    8月28日 美图公司 1357 HK 正式披露了2023中期业绩 报告期内 公司实现总收入12 61亿元 人民币 下同 同比增长29 8 经调整后归属于母公司权益持有人的净利润1 51亿元 同比增长320 4 从财报上看 美图公司上半年的收
  • python+pywinauto+lackey实现pc端exe自动化

    python pywinauto lackey实现PC端exe自动化 欢迎阅读 框架介绍 环境搭建 Tim自动化 完整代码 写在最后 欢迎阅读 最近一年多一直在从事PC端exe的测试 也是趁着闲余时间 调研了下exe的自动化 核心框架为py
  • 剪绳子(剑指offer 14-1题)

    这道题我拿到之后觉得第一个比较麻烦的点就是分成多少段是不确定的 处理起来就比较抽象 于是自然联想到分段数处理 于是我构建了一个函数getMax int n int i 它用来求长为n的绳子分成i段的最大积 然后在调用处循环每一个可能的i 取
  • 国内最强推荐系统,保姆级学习路线!!(含时间分配规划)

    最近秋招快要结束了 然后一直有很多小伙伴经常在后台私信我计算机专业关于学习路线的问题 可能还是因为没有真正工作而感到迷茫 而我也作为科班生一路走来 真的深知如果没有一个明确的方向 真的很容易走弯路 浪费大把的时间 了解我的小伙伴知道 我毕业
  • 使用UIUC数据集进行汽车检测

    第一步骤 下载数据集 https pan baidu com s 1tk10m8fh 7 MT4NJ29my4g 密码 wdzr 第二步骤 编写代码 如下 import cv2 import numpy as np from os path
  • latex±号_latex中数学符号

    latex中数学符号 常见数学中的特殊符号 缺失 latex中符号3610 9 alpha alfa 阿耳法 beta beta 贝塔 gamma gamma 伽马 deta delta 德耳塔 epsilon epsilon 艾普西隆 z
  • console.writeline($“{}{}“);

    console writeline 作用是将 内容当做表达式 例如 class MyClass public int val 20 class Program static void MyMethod MyClass f1 int f2 f
  • python字典和集合属于无序序列吗_python-序列、集合及字典

    组合数据类型 1 集合类型 集合是多种元素的无序组合 元素独一性 集合用大括号 表示 元素用 分隔 用set函数建立 A set python123 p y t h o n 1 2 3 集合操作符 集合有四种基础运算方法 并 交 差 补 S
  • 关于pads生产文件的导出

    1 solder mask solder mask 是阻焊层出的是负片 它的设置一般如图所示 这个是一般常规设置 如果器件焊盘已经专门做了阻焊焊盘 则可以按如图所示设置 如果选择top层焊盘 设备设置可以选择缩放为4 如果选择solder
  • EVE-NG网卡桥接,带您走进更高级的实验

    原帖地址 http www mamicode com info detail 1819599 html 一 给EVE NG添加虚拟的物理网卡 不管什么样的网卡 方法都类似 为什么说是虚拟的物理网卡呢 这个VMnet1网卡本身就是虚拟出来的
  • 一篇文章让你了解大数据挖掘技术

    大数据如果想要产生价值 对它的处理过程无疑是非常重要的 其中大数据分析和大数据挖掘就是最重要的两部分 在前几期的科普中 小编已经为大家介绍了大数据分析的相关情况 本期小编就为大家讲解大数据挖掘技术 让大家轻轻松松弄懂什么是大数据挖掘技术 什
  • 01 Datafountain_云状识别_top1

    01 Datafountain 云状识别 top1 摘要 1 云状识别算法总体思路和架构 2 云状识别算法具体实现过程 2 1 图像增强 2 2 多图像尺寸训练 2 3 选用densenet161预训练模型进行fine tune 2 4 差
  • Kotlin-Retrofit2和Rxjava2的网络封装,展示Github的用户信息

    目录 开始 1 先添加依赖 2 封装请求类 3 RESTful API请求响应的处理 4 线程与生命周期 5 使用 效果如下 开始 1 先添加依赖 Retrofit相关 implementation com squareup okhttp3
  • git did not exit cleanly (exit code 128) 的解决办法

    问题描述 在新建一个空的本地git仓库后 打算将远程仓库中的代码Pull到本地时异常 具体异常内容如下 git exe pull progress v no rebase origin masterPOST git upload pack
  • CRC-16校验原理

    1 循环校验码 CRC码 是数据通信领域中最常用的一种差错校验码 其特征是信息字段和校验字段的长度可以任意选定 2 生成CRC码的基本原理 任意一个由二进制位串组成的代码都可以和一个系数仅为 0 和 1 取值的多项式一一对应 例如 代码10
  • 【LeetCode】349. 两个数组的交集

    题目 给定两个数组 编写一个函数来计算它们的交集 示例 1 输入 nums1 1 2 2 1 nums2 2 2 输出 2 示例 2 输入 nums1 4 9 5 nums2 9 4 9 8 4 输出 9 4 说明 输出结果中的每个元素一定
  • Go语言面试题--基础语法(14)

    文章目录 1 切片 a b c 的长度和容量分别是多少 2 下面代码中 A B 两处应该怎么修改才能顺利编译 3 下面代码输出什么 1 切片 a b c 的长度和容量分别是多少 func main s 3 int 1 2 3 a s 0 b
  • 【科普向】谁都能看懂的CRC(循环冗余校验)原理

    CRC原理 简介 CRC基本原理 模二运算 二进制系数多项式 CRC算法 示例 CRC算法的数学描述 常用CRC版本 CRC算法的编程实现 简介 循环冗余校验 Cyclic Redundancy Check CRC 是一种根据网络数据包或计
  • MySQL - MySQL 8.0(二)基本操作:用户

    文章目录 前言 查看当前登录用户 一 创建用户 1 语法介绍 2 创建 dbadmin 用户 仅做了解 二 授予和撤销用户的访问权限 1 授予权限 2 检查授权 3 撤销权限 题外话 修改 mysql user 表 三 修改密码 身份验证插
  • 浅显易懂的GCC使用教程——初级篇

    浅显易懂的GCC使用教程 初级篇 2018 12 17天气暖 属于冬日里出太阳 最近在学习使用gvim 想着抛弃对IDE的依赖同时也是想了解编译的过程 但除了学习gvim繁多的指令外还得先学习使用gcc编译程序 这篇文章将会用浅显易懂的方式