编译器依赖
我在哪里可以下载免费的 C++ 编译器?
请查看以下(按供应商名称字母顺序排列):
- Clang (LLVM)
- Digital Mars。
- DJGPP 是 GCC 3.2 到 DOS 的移植,包括 RHIDE,一个基于 DOS 的 IDE。
- Embarcadero 免费提供一个命令行编译器。
- Microsoft Visual C++ 命令行编译器(2003 版)。
- MinGW 有一个 GCC 3.2 的移植版,可在 MS Windows 上运行。
另请查看这些列表:
我在哪里可以获得有关使用 MFC 和 Visual C++ 的更多信息?
以下是一些资源(不分先后):
www.visionx.com/mfcpro/
www.mvps.org/vcfaq
www.flounder.com/mvp_tips.htm
msdn.microsoft.com/archive/en-us/dnarvc/html/msdn_mfcfaq50.asp
如何使用 MFC 在状态栏中显示文本?
使用以下代码片段:
CString s = "Text";
CStatusBar* p =
(CStatusBar*)AfxGetApp()->m_pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR);
p->SetPaneText(1, s);
这适用于 MFC v.1.00,希望它也能适用于其他版本。
如何将可执行程序反编译回 C++ 源代码?
你一定是在开玩笑,对吧?
以下是这甚至几乎不可行的“许多”原因中的一部分:
- 你为什么认为这个程序最初是用 C++ 编写的?
- 即使你确定它最初(至少部分地)是用 C++ 编写的,那么是哪一个数不清的 C++ 编译器生成的它?
- 即使你知道编译器,使用的是哪个特定版本的编译器?
- 即使你知道编译器的制造商和版本号,使用了哪些编译时选项?
- 即使你知道编译器的制造商和版本号以及编译时选项,链接了哪些第三方库,它们的版本是什么?
- 即使你知道所有这些信息,大多数可执行文件都已剥离了调试信息,因此反编译后的代码将完全不可读。
- 即使你了解编译器、制造商、版本号、编译时选项、第三方库和调试信息的所有信息,编写一个适用于哪怕一个特定编译器且生成代码成功率适中的反编译器成本也将很高——与从头开始编写编译器本身相当。
但最大的问题不是“如何”反编译别人的代码,而是“为什么要”这样做?如果你试图逆向工程别人的代码,那真是羞耻;去找一份诚实的工作。如果你试图从丢失自己的源代码中恢复,我最好的建议是下次做好更好的备份。
(别费心给我发邮件说反编译有正当理由;我没说没有。)
我在哪里可以获得关于 {IBM, Microsoft, Sun 等} 的 C++ 编译器的信息?
按供应商名称字母顺序排列:
- Clang (LLVM):
clang.llvm.org/
- Comeau C++:
www.comeaucomputing.com/
- Digital Mars (免费) C++:
www.digitalmars.com/
- DJ C++ (“DJGPP”):
www.delorie.com/
- Edison Design Group C++:
www.edg.com/cpp.html
- GNU C++ (“g++” 或 “GCC”):
gcc.gnu.org/
。注意:Win32 有两个预编译版本:Cygwin 和 minGW。 - HP C++:
www.tru64unix.compaq.com/linux/compaq_cxx/index.html
- IBM VisualAge C++:
www.ibm.com/software/ad/vacpp/
- Intel Reference C++:
developer.intel.com/software/products/compilers/
- KAI C++:
developer.intel.com/software/products/kcc/
- Metrowerks C++:
metrowerks.com
或www.metrowerks.com
- Microsoft Visual C++:
msdn.microsoft.com/visualc/
- Open Watcom C++ (Watcom C++ 的开源后续):
www.openwatcom.org/
- Portland Group C++:
www.pgroup.com
- Silicon Graphics C++:
www.sgi.com/developers/devtools/languages/c++.html
- Watcom C++:
www.sybase.com/products/archivedproducts/watcomc
【如果有人有其他建议应列入此列表,请告知我们。谢谢。】
C++ 和 Visual C++ 有什么区别?
C++ 是语言本身,Visual C++ 是一个试图实现该语言的编译器。
编译器如何使用“过度分配”来记住已分配数组中的元素数量?
回想一下,当你 `delete[]` 一个数组时,运行时系统神奇地知道要运行多少个析构函数。本 FAQ 描述了一些 C++ 编译器实现此目的的技术(另一种常见技术是使用关联数组)。
如果编译器使用“过度分配”技术,则 `p = new Fred[n]` 的代码类似于以下内容。请注意,`WORDSIZE` 是一个假想的机器相关常量,至少为 `sizeof(size_t)`,可能会向上舍入以满足任何对齐约束。在许多机器上,此常量的值将为 4 或 8。它不是您的编译器将定义的真实 C++ 标识符。
// Original code: Fred* p = new Fred[n];
char* tmp = (char*) operator new[] (WORDSIZE + n * sizeof(Fred));
Fred* p = (Fred*) (tmp + WORDSIZE);
*(size_t*)tmp = n;
size_t i;
try {
for (i = 0; i < n; ++i)
new(p + i) Fred(); // Placement new
}
catch (...) {
while (i-- != 0)
(p + i)->~Fred(); // Explicit call to the destructor
operator delete[] ((char*)p - WORDSIZE);
throw;
}
然后 `delete[] p` 语句变为:
// Original code: delete[] p;
size_t n = * (size_t*) ((char*)p - WORDSIZE);
while (n-- != 0)
(p + n)->~Fred();
operator delete[] ((char*)p - WORDSIZE);
请注意,传递给 `operator delete[]` 的地址与 `p` 不同。
与关联数组技术相比,这种技术更快,但对程序员说 `delete p` 而不是 `delete[] p` 的问题更敏感。例如,如果您犯了编程错误,在应该说 `delete[] p` 的地方说了 `delete p`,则传递给 `operator delete(void*)` 的地址不是任何有效堆分配的地址。这可能会损坏堆。砰!你死了!
编译器如何使用“关联数组”来记住已分配数组中的元素数量?
回想一下,当你 `delete[]` 一个数组时,运行时系统神奇地知道要运行多少个析构函数。本 FAQ 描述了一些 C++ 编译器实现此目的的技术(另一种常见技术是过度分配)。
如果编译器使用关联数组技术,则 `p = new Fred[n]` 的代码类似于这样(其中 `arrayLengthAssociation` 是一个隐藏的全局关联数组的假想名称,它将 `void*` 映射到 `size_t`):
// Original code: Fred* p = new Fred[n];
Fred* p = (Fred*) operator new[] (n * sizeof(Fred));
size_t i;
try {
for (i = 0; i < n; ++i)
new(p + i) Fred(); // Placement new
}
catch (...) {
while (i-- != 0)
(p + i)->~Fred(); // Explicit call to the destructor
operator delete[] (p);
throw;
}
arrayLengthAssociation.insert(p, n);
然后 `delete[] p` 语句变为:
// Original code: delete[] p;
size_t n = arrayLengthAssociation.lookup(p);
while (n-- != 0)
(p + n)->~Fred();
operator delete[] (p);
Cfront 使用了这种技术(它使用 AVL 树来实现关联数组)。
与过度分配技术相比,关联数组技术较慢,但对程序员说 `delete p` 而不是 `delete[] p` 的问题不那么敏感。例如,如果您犯了编程错误,在应该说 `delete[] p` 的地方说了 `delete p`,则数组中只有第一个 `Fred` 被析构,但堆“可能”会幸存下来(除非您已用不简单调用 `operator delete` 的东西替换了 `operator delete[]`,或者除非其他 `Fred` 对象的析构函数是必需的)。
如果名称修饰标准化,我能否链接由不同编译器供应商编译的代码?
简短回答:可能不能。
换句话说,有些人希望将名称修饰标准纳入拟议的 C++ ANSI 标准中,以避免不得不为不同的编译器供应商购买不同版本的类库。然而,名称修饰差异是实现之间最小的差异之一,即使在同一平台上也是如此。
以下是其他差异的部分列表:
- 成员函数的隐藏参数的数量和类型。
- `this` 是否被特殊处理?
- 按值返回指针在哪里传递?
- 假设使用v-table
- 它的内容和布局是什么?
- 对于多重和/或`virtual`继承,`this`的调整在哪里/如何进行?
- 类的布局方式,包括
- 基类的位置?
- 如何处理`virtual`基类?
- v-pointers的位置,如果它们被使用的话?
- 函数的调用约定,包括
- 实际参数放在哪里?
- 实际参数按什么顺序传递?
- 寄存器如何保存?
- 返回值去哪里?
- 调用后是调用者还是被调用者弹出栈?
- 传递或返回结构体或双精度浮点数的特殊规则?
- 调用叶函数时保存寄存器的特殊规则?
- 运行时类型识别是如何布局的?
- 运行时异常处理系统如何知道在抛出异常期间需要析构哪些局部对象?
GNU C++ (g++) 为微小程序生成巨大的可执行文件;为什么?
libg++(g++ 使用的库)可能是在包含调试信息(`-g`)的情况下编译的。在某些机器上,不带调试信息重新编译 libg++ 可以节省大量磁盘空间(大约 1 MB;缺点:你将无法跟踪 libg++ 调用)。仅仅 `strip` 可执行文件并不能像不带 `-g` 重新编译然后 `strip` 生成的 `a.out` 那样节省空间。
使用 `size a.out` 来查看程序代码和数据段的实际大小,而不是 `ls -s a.out`,后者包含了符号表。
有可供 `yacc` 处理的 C++ 语法吗?
您主要想要的 `yacc` 语法来自 Ed Willink。Ed 认为他的语法完全符合ISO/ANSI C++ 标准,但他不作保证:“该语法尚未,”他说,“被实际使用过。”您可以获取不带动作例程的语法或带虚拟动作例程的语法。您还可以获取相应的词法分析器。对于那些对他是如何实现上下文无关解析器感兴趣的人(通过将所有歧义以及少数在解析完成后进行的修复推迟),您可能想阅读他的论文的第 4 章。
还有一个非常旧的 `yacc` 语法,不支持模板、异常和命名空间;此外,它在某些微妙方面偏离了核心语言。您可以在这里或这里获取该语法。
什么是 C++ 1.2?2.0?2.1?3.0?
这些不是语言的版本,而是Cfront的版本,Cfront 是 AT&T 实现的原始 C++ 转换器。现在普遍接受将这些版本号视为语言本身的版本。
“非常”粗略地说,这些是主要功能:
- 2.0 包括多重/`virtual`继承和纯虚函数
- 2.1 包括半嵌套类和 `delete[] pointerToArray`
- 3.0 包括完全嵌套类、模板和 `i++` vs. `++i`
- 4.0 将包括异常
是否可以将 C++ 转换为 C?
取决于你的意思。如果你是问“是否可以将 C++ 转换为可读可维护的 C 代码?”,那么抱歉,答案是否定的——C++ 的特性无法直接映射到 C,而且生成的 C 代码不适合人类阅读。如果你是问“是否有可以将 C++ 转换为 C 以便在尚未拥有 C++ 编译器的平台上进行编译的编译器?”,那么你很幸运——请继续阅读。
一个将 C++ 编译为 C 的编译器会对程序进行完整的语法和语义检查,并且只是恰好使用 C 代码作为生成目标代码的一种方式。这种编译器不仅仅是一种花哨的宏处理器。(请不要给我发邮件说这些是预处理器——它们不是——它们是完整的编译器。)通过转换为 C 来实现 ISO 标准 C++ 的所有功能是可能的,除了异常处理,它通常会生成与传统 C++ 编译器生成的代码效率相当的目标代码。
以下是一些执行编译到 C 的产品(注意:如果您知道任何其他执行此操作的产品,请告知我们)
- Comeau Computing 提供基于 Edison Design Group 前端的编译器,该编译器输出 C 代码。
- LLVM 是一个可下载的编译器,它会发出 C 代码。另请参阅这里和这里。
- Cfront,由 Bjarne Stroustrup 和 AT&T 的其他人实现的 C++ 原始实现,生成 C 代码。然而它有两个问题:自 90 年代中期开始经历所有权变更的迷宫以来,它一直难以获得许可,而且开发也在同一时间停止,因此它没有错误修复,也不支持任何新的语言特性(例如,异常、命名空间、RTTI、成员模板)。
- 与流行传闻相反,截至本文撰写之时,没有将 C++ 转换为 C 的 g++ 版本。这种事情似乎是可行的,但我不知道有人实际做过(目前)。
请注意,您通常需要指定目标平台的 CPU、操作系统和 C 编译器,以便生成的 C 代码能够专门针对该平台。这意味着:(a) 您可能无法将为平台 X 生成的 C 代码在平台 Y 上编译;(b) 自己进行转换会很困难——使用其中一个工具可能会更便宜/更安全。
再说一遍:请不要给我发邮件说这些只是预处理器——它们不是——它们是编译器。