bhu*_*ups 13 c preprocessor programming-languages
我想知道为什么其他语言不支持此功能.我可以理解C/C++代码是依赖于平台的,因此可以通过使用预处理器指令实现跨各种平台的工作(编译和执行).除此之外,还有许多其他用途.就像你可以将所有调试printf放在里面#if DEBUG ... #endif
.因此,在发布版本时,这些代码行不会在二进制文件中编译.
但在其他语言中,实现这个(后面的部分)是困难的(或者可能是不可能的,我不确定).所有代码都将在二进制文件中编译,增加其大小.所以我的问题是"为什么Java, or other modern compiled languages
不支持这种功能?" 它允许您以非常方便的方式包含或排除二进制文件中的某些代码.
没有预处理器的主要语言通常具有不同的,通常更清晰的方式来实现相同的效果.
拥有像文本预处理器一样cpp
是混合的祝福.由于cpp
实际上并不知道C,它所做的只是将文本转换为其他文本.这会导致许多维护问题.以C++为例,其中明确弃用了预处理器的许多用法,以支持更好的功能,例如:
const
而不是#define
inline
而不是#define
宏C++ FAQ 调用了macros,并提供了多种理由来避免使用它们.
滥用的可能性远远超过预处理器的可移植性优势. 以下是我在业界看到的实际代码中的一些示例:
功能体变得如此纠结,#ifdef
以至于很难读取功能并弄清楚发生了什么.请记住,预处理器使用的是文本而不是语法,因此您可以执行非常不合理的事情
代码可能会在不同的分支中重复#ifdef
,因此很难保持关于正在发生的事情的单一事实.
当应用程序用于多个平台时,编译所有代码变得非常困难,而不是为开发人员平台选择的任何代码.您可能需要设置多台计算机.(例如,在BSD系统上设置一个准确模拟GNU标头的交叉编译环境是很昂贵的.)在大多数Unix专有且供应商必须全部支持它们的时代,这个问题非常严重.今天,当这么多版本的Unix都是免费的时候,它不是一个问题,尽管在Unix环境中复制本机Windows头文件仍然非常具有挑战性.
它有些代码受到许多代码的保护#ifdef
,你无法弄清楚-D
选择代码需要哪些选项组合. 问题是NP难,所以最着名的解决方案需要尝试指数多种不同的定义组合.这当然是不切实际的,所以真正的结果是你的系统逐渐填充了尚未编译的代码.这个问题会导致重构,当然这样的代码完全不受你的单元测试和回归测试的影响 - 除非你建立一个庞大的多平台测试服务器场,甚至可能不会.
在现场,我已经看到这个问题导致重构应用程序经过仔细测试和发货的情况,只接收应用程序甚至无法在其他平台上编译的即时错误报告.如果代码被隐藏#ifdef
,我们无法选择它,我们无法保证它是类型检查 - 甚至它在语法上是正确的.
硬币的另一面是更先进的语言和编程技术减少了预处理器中条件编译的需要:
对于某些语言,如Java,所有与平台相关的代码都在JVM的实现中以及相关的库中.人们已经竭尽全力制作与平台无关的JVM和库.
在许多语言中,例如Haskell,Lua,Python,Ruby等等,与C相比,设计人员在减少与平台相关的代码量方面遇到了一些麻烦.
在现代语言中,您可以将依赖于平台的代码放在编译接口后面的单独编译单元中.许多现代编译器都具有跨接口边界内联函数的良好工具,因此您不需要为这种抽象支付太多(或任何)惩罚.这不是C的情况,因为(a)没有单独编译的接口; 单独编译模型假设#include
和预处理器; (b)C编译器在具有64K代码空间和64K数据空间的机器上成熟; 一个足够复杂的编译器可以跨模块边界内联,这几乎是不可想象的.今天这样的编译器是常规的.一些高级编译器动态地内联和专门化方法.
简介:通过使用语言机制而不是文本替换来隔离依赖于平台的代码,您将所有代码暴露给编译器,至少对所有内容进行类型检查,并且您有可能执行静态分析以确保合适测试覆盖率.您还排除了一大堆编码实践,导致代码无法读取.
因为现代编译器在任何情况下都足够聪明地删除死代码,因此不再需要以这种方式手动馈送编译器.即代替:
#include <iostream>
#define DEBUG
int main()
{
#ifdef DEBUG
std::cout << "Debugging...";
#else
std::cout << "Not debugging.";
#endif
}
Run Code Online (Sandbox Code Playgroud)
你可以做:
#include <iostream>
const bool debugging = true;
int main()
{
if (debugging)
{
std::cout << "Debugging...";
}
else
{
std::cout << "Not debugging.";
}
}
Run Code Online (Sandbox Code Playgroud)
你可能会获得相同或至少相似的代码输出.
编辑/注意:在C和C++中,我绝对不会这样做 - 我会使用预处理器,如果没有别的东西,它会立即让我的代码的读者清楚它的一大块不应该在某些条件下遵守.然而,我说,这就是许多语言避开预处理器的原因.