- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
对于由C开发的大型软件,我们首先在一个单独的头文件(例如myfun.h
)中声明所有自定义函数。之后,一旦编写了使用main.c
中列出的功能的代码(例如myfun.h
),就必须#include "myfun.h"
。我想知道它是如何工作的,因为即使我在主体之前包括在头文件中声明的函数名称,代码也无法在main.c
中看到函数的详细信息。我想它将搜索库以获取功能详细信息...对吗?
最佳答案
当您说“它将在库中搜索函数的详细信息”时,您虽然相距不远,但这并不完全正确。函数声明,即函数原型仅包含足够的信息,供编译器执行以下两项操作:
首先,编译器会将函数注册为已知的标识符,这样它就知道您在调用函数时所要处理的事情,这与带有括号的随机字母字符串相对(对于编译器,它们本质上是相同的,没有函数原型-错误)。
其次,编译器使用函数原型检查代码正确性。在这种意义上的正确性意味着函数调用将在原型和类型上都与原型匹配。换句话说,对int square(int a, int b);
的函数调用将具有两个参数,均为整数。
但是,该程序不会“搜索库”。不带括号的函数名称不是函数调用,而是函数的地址。因此,当您调用一个函数时,处理器将跳转到该函数的内存位置。 (这假定该函数尚未内联。)
但是此功能在哪里?这取决于。如果您在同一模块中编写函数,即,将.c文件编译为与main.c文件链接为单个可执行文件的对象,则该函数的位置将位于可执行文件。换句话说,它与主函数的入口点仅有一点偏移。在大型项目中,此偏移量不会太小,但会比单独对象的偏移量短。
话虽如此,如果您将这个假设函数编译成一个DLL,然后从主程序中调用该DLL,则该函数的地址将通过以下两种方式之一确定:
您将生成一个.lib / .a吗? (取决于您使用的是Windows还是Linux)文件,其中包含函数声明的和地址,或者:
您将使用运行时链接,当主程序将.dll / .so加载到其地址空间时,该程序将在其中计算函数地址。首先,它将确定将其加载到何处。您可以将DLL设置为具有首选偏移量,以优化加载时间。否则,库将从可用的第一个段开始加载,并且任何其他库将需要使用此新地址重新计算其功能地址,这会影响初始加载时间。但是,一旦将它们加载到程序的内存中,此后就不会对性能造成任何影响。
回到预处理器,注意两点很重要。首先,它在任何编译发生之前运行。这个很重要。由于在预处理程序执行操作时并未真正“编译”程序,因此宏不是类型安全的。 (插入Haskell关于C“类型安全”的笑话)这就是为什么您不-或不应该-看到C ++中的宏的原因。使用C中的宏可以完成的任何事情都可以通过const
和C ++中的内联函数来完成,并具有类型安全性的额外好处。
其次,预处理器几乎只是一个搜索和替换引擎。例如,在以下代码中,什么都没有发生,因为预处理器if
语句的计算结果为false,因为我从未定义任何内容。预处理程序将删除此部分中的代码。请记住,由于编译器尚未认真运行,因此删除的代码将无法编译。通常利用此事实来实现用于调试或登录调试版本的功能。在发行版本中,预处理器定义随后被处理,以便不包括调试代码。
#include <stdio.h>
#include <stdlib.h>
int main()
{
#if TRUE
printf("Hello, World!");
#endif
return EXIT_SUCCESS;
}
EXIT_SUCCESS
宏在stdlib.h中定义,并由
0
代替。 (EXIT_FAILURE = 1)。
// Not valid C89, possibly even C99
const int DEFAULT_BUFFER_SIZE = 128;
char user_input[DEFAULT_BUFFER_SIZE];
// Legal since the dawn of time
#define DEFAULT_BUFFER_SIZE 128
char user_input[DEFAULT_BUFFER_SIZE];
#ifdef WIN32
// Do windows things
#elif
// Handle other OS
#endif
void RequestSomeKernelAction();
#ifdef WIN32
RequestSomeKernelAction = WindowsVersion;
#else
RequestSomeKernelAction = OtherOSFunction;
#endif
#ifndef SRC_INCLUDES_TEST_H
#define SRC_INCLUDES_TEST_H
int square(int a);
#endif /** SRC_INCLUDES_TEST_H */
#define SRC_INCLUDES_TEST_H
#include "test.h"
int main()
{
int n = square(4);
}
square
的头文件,但是我的
#define SRC_INCLUDES_TEST_H
语句告诉预处理器将所有头文件的内容复制到main上,但块中的内容除外。
SRC_INCLUDES_TEST_H
被定义,即..什么都没有。
关于c - 在C主体中包含头文件的机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49635140/
我有一位客户希望她的网站适合 iPad/iPhone。该网站有一个用 Flash 制作的菜单标题。我使用 Google 的 Swiffy 将文件转换为 flash_1.html 文件。 当网站检测到
我注意到 boost 库使用了 (.hpp) 的头文件。 我很好奇,因为我看到的大多数源文件都使用普通的 .h 头文件。 是否有任何特殊情况需要使用 .hpp 而不是 .h ? 谢谢 最佳答案 只是约
C需要不同的头文件,如stdio.h、stdlib.h、fcntl.h等,对于不同的函数和结构定义,这是为什么?在幕后,一切都归结为 libc 那么为什么不创建一个包含所有定义和原型(prototyp
我是一名工科学生,不是一个非常强大的程序员。我的一项作业包括使用 openGL 创建 VR 程序。我得到了一个使用 gmtl 的模板(我真的不想重写)标题广泛。该作业需要实现一些 sixense模拟中
我正在尝试编译涉及C和C++文件的应用程序。使用一个特定的 header ,我遇到了问题。有问题的文件(C++头文件)如下所示: #ifndef TASK_H #define TASK_H #incl
我编写了我的项目,将main和c源代码保存在一个文件中,并将头文件保存在codeblocks的include目录中。当我从项目主函数中调用我的函数时,它编译得很好......但是当我将 header
我正在尝试将 .so 库导入到 python 代码中以使用 c 函数。我认为使用 from ctypes import * import ctypes lib = CDLL('./libcaenhvw
我有 2 个重叠的头文件,如下所示: header1.h ... __declspec(dllexport) void abc(); __declspec(dllexport) void xyz(
我有一个大型 Java 库,我想开发几个与该库接口(interface)的较小应用程序。该库将作为 JAR 出现在目标设备的类路径中,但我想尽可能避免在编译时出现整个库(JAR 或源代码)。 (如果重
我必须在我的项目中使用相机制造商提供的库。我正在使用 Visual Studio 2015。我在编写#include 后合并了VS 2015 建议的所有头文件。 我已经在VS 2015中指定了包含文件
我在编写我的项目时遇到了这个问题。我有 2 个 header ,每个 header 都有一个类,它们需要另一个,如下所示。 我以为这只是需要使用前向声明,但仍然不起作用。我没有想法。 寻求帮助:D H
我在一个项目中工作,我想在C++中做反射,所以经过研究我发现最好的方法是解析头文件以获得XML格式的抽象语法树并在反射中使用它。我尝试了很多工具,但没有一个与 visual c++ 2008 或 vi
我尝试从 BufferedImage 制作一个 BMP 文件。这是我尝试在 bmp 文件中写入标题和像素的函数。 我有一个错误,但我找不到那个。我需要你的帮助。 static void writeTo
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: undefined reference to `WinMain@16' 我一直在研究循环双链表。决定创建一个
处理这种情况的最佳做法是什么? class A { private: std::vector derp; public: struct B { ...
上下文:我正在为嵌入式板构建一些代码。它需要安装 Xilinx 工具、Linaro 工具链,然后调用开发板构建目录中的设置 bash 脚本(我们称之为 setup.sh)。 如果我不运行 setup.
我尝试使用头文件和源文件,但遇到了问题。因此,我对我正在尝试做的事情做了一个简化版本,我在 CodeBlocks 中遇到了同样的错误(undefined reference to add(double
当我包含用于将某些程序的整数类型转换为字符串类型的#include 头文件时,我的编译器(GCC for C++)抛出错误。谁能帮我解决这个问题? 这是一个C++的小代码,我是第一次尝试。 #incl
我的头文件中有一些错误,我不知道如何修复,因为我是 C++ 的新手。 这是头文件的代码: #pragma once typedef unsigned int uint; class DCEncrypt
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我是一名优秀的程序员,十分优秀!