AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79591978
Accepted
Newton's in-law
Newton's in-law
Asked: 2025-04-25 15:08:32 +0800 CST2025-04-25 15:08:32 +0800 CST 2025-04-25 15:08:32 +0800 CST

标准 C 文件是否编译?

  • 772

每当我们创建一个包含自定义函数定义的文件,例如,以及包含函数声明的utils.c相应头文件时,我必须使用类似 的命令将该文件与我正在使用的驱动程序代码一起编译。utils.hutils.cgcc driver.c utils.c -o my_exe

那么什么指令可以编译我们包含其头文件的标准 C 文件stdio.h?

c
  • 5 5 个回答
  • 156 Views

5 个回答

  • Voted
  1. Best Answer
    Gerhard
    2025-04-25T19:29:17+08:002025-04-25T19:29:17+08:00

    编译分为三个步骤:预处理、编译和链接。

    gcc driver.c utils.c -o my_exe是以下的简写:

    gcc -c driver.c -o driver.o
    gcc -c utils.c -o utils.o
    ld driver.o utils.o -o my_exe
    

    即编译驱动程序、编译实用程序,然后将所有内容链接在一起。

    这里仍然不太清楚的是,includes 被复制到 c 文件中进行编译。以下步骤进一步分解,以显示处理头文件中代码的预处理过程:

    gcc -E driver.c -o driver.i
    gcc driver.i -o driver.o
    gcc -E utils.c > utils.i
    gcc utils.i -o utils.o
    ld driver.o utils.o -o my_exe
    

    gcc driver.o utils.o -o my_exe也可以更改包含库,例如-lm包含标准数学库(libm.a 或 libm.so)。库只是.o容器文件中预编译的 C 源代码(目标代码或)。

    标准库(如stdlib.h和stdio.h)是libc.so(或libc.a)。您无需显式链接它们,但如果您愿意,也可以这样做。

    然后gcc driver.o utils.o -o my_exe变成gcc driver.o utils.o -o my_exe -lc

    您可以按照相同的方式预编译代码以供稍后链接:

    gcc -c utils.c -o utils.o
    ar rcs libUtils.a utils.o
    gcc driver.c -L. -lUtils -o my_exe
    
    • 4
  2. Reny Paul
    2025-04-25T15:31:55+08:002025-04-25T15:31:55+08:00

    使用它进行编译时,gcc driver.c utils.c -o my_exe将跳过创建相应的 .o 文件。由于最终输出需要 driver.c 和 utils.c 的更改,因此每次这两个文件发生任何更改时,您都需要运行此命令。如上一条回复所述,标准 c 文件被编译为静态或动态库,这些库将由相应的软件包所有者创建,并作为任何操作系统软件包的一部分供用户使用,例如 libc-dev。
    为了避免在特定文件中没有修改时进行编译,您可以使用 Makefile 创建一个中间的“.o”文件,例如

    my_exe: driver.o utils.o
        gcc driver.o utils.o -o my_exe
    
    driver.o: driver.c
        gcc -c driver.c driver.o
    utils.o: utils.c
        gcc -c utils.c utils.o
    
    • 2
  3. Eric Postpischil
    2025-04-25T18:20:01+08:002025-04-25T18:20:01+08:00

    那么什么指令可以编译我们包含其头文件的标准 C 文件stdio.h?

    在大多数 C 实现中,标准 C 库的源代码已经为您准备好并打包到“库”文件中。

    标准库的源代码被编译或汇编成目标模块,这些目标模块被插入到静态或动态库文件中。库文件很大程度上只是目标模块的集合。

    GCC 和 Clang 在链接时默认包含标准库。(这会带来一些麻烦,例如某些实现需要额外的-lm开关才能包含标准库的数学例程。)gccorclang命令(以及其他一些变体,例如g++)实际上是一个“前端”,它会根据您传递的参数的需要,调用编译器和/或汇编器和/或链接器。如果您使用开关-v,它们将显示它们执行的命令,并且链接命令将包含一个或多个库文件。

    • 2
  4. Hermit
    2025-04-25T19:11:44+08:002025-04-25T19:11:44+08:00

    当您包含#include <stdio.h> (添加输入/输出函数,如printf)用于内存管理#include <stdlib>、字符串操作#include <string.h>等时,会发生这种情况...您告诉编译器复制声明printf,scanf等...这些函数位于头文件中,如stdio.h,stdlib等...这些文件的代码已经编译,它们是 GNU C 库的一部分。

    您可以尝试详细了解这些文件的位置

    gcc -v your_program.c -o your_program

    输出将如下所示

    $ gcc -v test.c -o test.o 
    Using built-in specs. 
    COLLECT_GCC=gcc 
    COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper 
    OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa 
    OFFLOAD_TARGET_DEFAULT=1 
    Target: x86_64-linux-gnu 
    Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-fG75Ri/gcc-13-13.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-fG75Ri/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 
    Thread model: posix 
    Supported LTO compression algorithms: zlib zstd 
    gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04)  
    COLLECT_GCC_OPTIONS='-v' '-o' 'test.o' '-mtune=generic' '-march=x86-64' '-dumpdir' 'test.o-' 
    /usr/libexec/gcc/x86_64-linux-gnu/13/cc1 -quiet -v -imultiarch x86_64-linux-gnu test.c -quiet -dumpdir test.o- -dumpbase test.c -dumpbase-ext .c -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccRbksbn.s
    GNU C17 (Ubuntu 13.3.0-6ubuntu2~24.04) version 13.3.0 (x86_64-linux-gnu) 
        compiled by GNU C version 13.3.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP 
     
    GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 
    ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" 
    ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu" 
    ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed" 
    ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include" 
    #include "..." search starts here: 
    #include <...> search starts here: 
    /usr/lib/gcc/x86_64-linux-gnu/13/include
    /usr/local/include
    /usr/include/x86_64-linux-gnu
    /usr/include
    End of search list. 
    Compiler executable checksum: 38987c28e967c64056a6454abdef726e 
    COLLECT_GCC_OPTIONS='-v' '-o' 'test.o' '-mtune=generic' '-march=x86-64' '-dumpdir' 'test.o-' 
    as -v --64 -o /tmp/ccwriUWR.o /tmp/ccRbksbn.s
    GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42 
    COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/ 
    LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/ 
    COLLECT_GCC_OPTIONS='-v' '-o' 'test.o' '-mtune=generic' '-march=x86-64' '-dumpdir' 'test.o.' 
    /usr/libexec/gcc/x86_64-linux-gnu/13/collect2 -plugin /usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper -plugin-opt=-fresolution=/tmp/ccO6Fe7I.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o test.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/13 -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/13/../../.. /tmp/ccwriUWR.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o
    COLLECT_GCC_OPTIONS='-v' '-o' 'test.o' '-mtune=generic' '-march=x86-64' '-dumpdir' 'test.o.'
    

    这里你可以看到三个阶段:

    1. 通过调用和将文件编译.c为目标文件。.occ1as

    2. 将这些目标文件与启动文件(Scrt1.o、、)和预建的 C 运行时库(GCC 的支持库和 C 标准库)crti.o链接在一起。crtn.o

    3. 结果就是您的最终可执行文件。

    在详细转储中,关键行隐藏在collect2/ld调用中:

    … -plugin-opt=-pass-through=-lc … -lc …

    这-lc是链接器标志,它告诉它:

    “引入 C 标准库 (libc),其中已经包含printf、fopen等的编译代码。”

    您无需自行编译stdio.c(或编译任何.cglibc 源代码)。C 库以预编译的存档(libc.a)和共享对象(libc.so)的形式提供,GCC 驱动程序会-lc在链接时自动传递,以便您的所有<stdio.h>声明都能解析为 libc 中的真实代码。

    值得一读的是https://www.gnu.org/software/libc/manual/html_node/Header-Files.html以及编译/链接过程如何工作?

    • 1
  5. sairaman g
    2025-04-25T19:49:32+08:002025-04-25T19:49:32+08:00

    标准 C 文件已经编译完毕,并且是 stdc++ 库及其链接库的一部分。在我的例子中,它位于

    /usr/lib/x86_64-linux-gnu/libstdc++.so.6
    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30.
    

    一个示例测试,用于检查 是否.so包含函数。我只是检查了 是否printf存在于 中libstdc++.so.6。

    readelf -a libstdc++.so.6 | grep printf
    
    000000226468  001f00000007 R_X86_64_JUMP_SLO 0000000000000000 \__fprintf_chk@GLIBC_2.3.4 + 0
    
    000000226ec0  005b00000007 R_X86_64_JUMP_SLO 0000000000000000 sprintf@GLIBC_2.2.5 + 0
    
    000000227448  007900000007 R_X86_64_JUMP_SLO 0000000000000000 vsnprintf@GLIBC_2.2.5 + 0
    
    000000227bb8  009f00000007 R_X86_64_JUMP_SLO 0000000000000000 \__sprintf_chk@GLIBC_2.3.4 + 0
    

    每个 gcc 版本都有对应的版本libstdc++.so,因此无法在低版本的 gcc 中运行用高版本 gcc 构建的可执行文件。因为低版本的 gcc 缺少所需的运行时符号。

    • 0

相关问题

  • 比 * 更快的乘法

  • 在 C 中的 scanf() 格式说明符中使用宏获取字符串长度

  • 如何将#define的数据类型设置为long double?

  • 不兼容的常量指针

  • OpenGL 中的非渐变颜色变化

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve