Differences Between Clang-enhanced C++ Compilers and Previous-Generation C++ Compilers
Go Up to Clang-enhanced C++ Compilers
This topic provides an overview of the differences between Clang-enhanced C++ compilers and their immediate predecessor, BCC32.
Contents
- 1 Command-Line Options
- 2 Stricter C++ Compiler
- 3 Warnings and Error Messages
- 4 Predefined Macros
- 5 #include Paths and Lookup
- 6 Precompiled Headers
- 7 Object and Library File Format
- 8 __property: Compound and Chained Assignment
- 9 Deprecated BCC32 Extensions and Keywords
- 10 Unsupported BCC32 Attributes
- 11 Unicode Identifiers Are Not Supported
- 12 Inline Assembly
- 13 Try Blocks Cannot Handle Some Exceptions
- 14 See Also
Command-Line Options
Clang-enhanced C++ compilers use an almost completely different set of command-line options, and a different way to express multiple values for the same option.
Stricter C++ Compiler
Clang-enhanced C++ compilers are more compliant with C++ language standards than BCC32. They provide C++11 support, but they are also more strict. See Stricter C++ Compilers (Clang-enhanced C++ Compilers).
Warnings and Error Messages
In addition to new, more specific and detailed warnings and error messages, Clang-enhanced C++ compilers phrase messages for conditions detected by BCC32 in a different way.
For more information, see Errors and Warnings of Clang-enhanced C++ Compilers.
Predefined Macros
Using Clang-enhanced C++ compilers you can get all the predefined macros directly from the preprocessor.
RTLVersion Macro
The RTLVersion constant is not supported by Clang-enhanced C++ compilers. Instead, you may use RTLVersionC.
NO_STRICT Macro
The NO_STRICT type checking scheme is not supported in Clang-enhanced C++ compilers. If you have existing projects that use the NO_STRICT conditional define, you need to remove it.
For more information and instructions for removing NO_STRICT, see: C++ Applications Use STRICT Type Checking.
#include
Paths and Lookup
You might need to #include
headers differently with Clang-enhanced compilers.
For example, Clang-enhanced C++ compilers do not find headers specified with semi-absolute paths as BCC32 does. Given that 'myOtherFile' is located at C/myProjectsDir/myOtherApp, the following references in a .CPP file are accepted by both Clang-enhanced C++ compilers and BCC32:
#include "c:/myProjectsDir/myApp/mySource.h" // Absolute path.
#include "../myApp/mySource.h" // Relative path.
However, the following yields an error with Clang-enhanced C++ compilers, but it is accepted by BCC32:
#include "/myProjectsDir/myApp/mySource.h" // Semi-absolute path.
Clang-enhanced C++ compilers emit the following error:
[<compiler> Fatal Error] myOtherFile.cpp(27): '/myProject/myApp/mySource.h' file not found
For more information, see Clang-enhanced C++ Compilers, #include Paths and Lookup.
Precompiled Headers
Compared to BCC32, precompiled headers work a little differently for Clang-enhanced C++ compilers. Each C++ project can have only one precompiled header, and a default precompiled header (named projectPCHn.h) is generated for each new C++ project.
For more information, see the following topics:
- Using Precompiled Headers with Clang-enhanced C++ Compilers
- Precompiled Headers Command Line Options for Clang-enhanced C++ Compilers
Object and Library File Format
- BCC32 and its associated tools use OMF in
.obj
and.lib
files. - Clang-enhanced C++ compilers use ELF in
.o
and.a
files.
This difference means, for example, that when you migrate a 32-bit Windows applications you must change references to .lib
and .obj
files to be .a
and .o
, respectively.
__property: Compound and Chained Assignment
Clang-enhanced C++ compilers support compound assignment of __property
, while BCC32 does not.
The objects of the keyword __property
are not like fields or members. They should be used in simple assignments.
Although both BCC32 and the RAD Studio Clang-enhanced C++ compilers allow __property
to be used in compound assignments such as:
Form1->Caption += DateToStr(Now());
BCC32 only invokes the getter, not the setter. Therefore we recommend that you avoid such constructs when targeting multiple platforms.
None of these compilers support the usage of __property in chained assignment, as in:
Button2->Caption = Button1->Caption = DateToStr(Now()); // Error
Deprecated BCC32 Extensions and Keywords
No-underscore and single-underscore compiler keyword extensions are either unsupported or deprecated in Clang-enhanced C++ compilers. Use the double-underscore versions (they are also supported in BCC32):
cdecl
,_cdecl
: Use__cdecl
.pascal
,_pascal
: Use__pascal
._fastcall
: Use__fastcall
, which is now Microsoft-style, not Borland-style._stdcall
: Use__stdcall
._fortran
,__fortran
: Not supported, obsolete.asm
,_asm
,__asm
: Inline assembly is not supported._export
: Use__export
._import
: Use__import
._declspec
: Use__declspec
.
Unsupported BCC32 Attributes
See Workaround for C++11 Attributes (noreturn and final).
Unicode Identifiers Are Not Supported
Although Unicode is supported in literal strings and file names, Unicode in identifiers is not allowed.
Inline Assembly
Clang-enhanced C++ compilers allow inline assembly with these caveats:
- You cannot mix assembly with C++ code.
- Do not touch the stack pointer (RSP).
- The assembler must use the AT&T line-by-line syntax, not the more familiar block-of-Intel syntax. For more information, see GCC-Inline-Assembly-HOWTO.
Clang-enhanced C++ compilers support inline assembly in a different style than the inline assembly supported by BCC32:
- Different Assembly syntax:
- The Assembly syntax supported by Clang-enhanced C++ compilers is line-by-line AT&T syntax, not the more familiar block-of-Intel syntax.
- Potential exception handling and debugging problems:
- The exception handling of the compiler places additional burdens on hand-written Assembly code intermixed with C++. Functions written entirely in assembly (with a separate assembler like NASM or MASM) can be linked into your program. However, there are inherent issues (potential exception handling and debugging problems) that you should know before you start.
- The reasons for these issues for inline assembly can be summarized as: pdata. Lack of support for inline assembly is fairly common; for exceptions (and debugging) to work, code has to generate data structures (pdata) that describe each function and what must be unwound if an exception is thrown. After you insert inline assembly, the compiler is unaware of finer details (like any extra stack space the inline assembly allocated). Inline assembly (that is, mixing assembly and C/C++ code) makes it impossible for the compiler to accurately generate the pdata structures. For more information about pdata, see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
For a code example illustrating how to use inline assembly with a Clang-enhanced C++ compiler, see Inline Assembly with BCC64 (C++).
For more information about assembly with Clang-enhanced C++ compilers, see:
- http://clang.llvm.org/compatibility.html#inline-asm
- http://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C
- http://wiki.osdev.org/Inline_Assembly/Examples
Try Blocks Cannot Handle Some Exceptions
Synchronous exceptions are exceptions raised using a throw statement in your program or in the libraries that your program uses. Compilers know where and when these exceptions raise.
Asynchronous exceptions are exceptions that come from the operating system and may raise at any time, such as divisions by zero or access violations.
Standard C and C++ are designed to handle synchronous exceptions only. However, when your C++Builder applications link to the RTL, you are adding your applications the ability to catch asynchronous exceptions as well.
However, Clang is designed for synchronous exceptions only, and it does not support non-call exception handling. If a try block contains no throw statements and no calls to functions that may contain throw statements, Clang ignores any catch and finally blocks associated with that try block. That is, if a try block cannot throw any synchronous exception, you cannot catch any asynchronous exception in that try block either.
For example:
float a = 1;
float b = 0;
try {
try {
a = a / b; // The RTL throws an asynchronous exception (division by zero).
}
__finally {
// Execution never reaches this point.
}
}
catch (...) {
// Execution never reaches this point.
}
Instead of catching these special exceptions that Clang-enhanced compilers cannot handle, you should do either of the following:
- Move the code that may raise an asynchronous exception to its own function and call that function from your try block.
- Try to prevent these exceptions from ever raising. For example, you could check the value of
b
before you perform the division.
- Note: If you do not handle asynchronous exceptions, the default exception handler of the GUI framework of your application catches them, and your application raises an External Exception EEFFACE.