C preprocessor: Difference between revisions

Content deleted Content added
No edit summary
 
(25 intermediate revisions by 9 users not shown)
Line 14:
}}</ref>
 
The [[C Sharp (programming language)|C#]] programming language also allows for directives, even though they are not read by a preprocessor and they cannot be used for creating macros, and isare generally more intended for features such as conditional compilation.<ref>{{cite web|url=https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives|title=C# preprocessor directives|date=14 January 2022 |publisher=Microsoft}}</ref> C# seldom requires the use of the directives, for example code inclusion does not require a preprocessor at all (as C# relies on a package/namespace system like Java, no code needs to be "included").
 
The [[Haskell]] programming language also allows the usage of the C preprocessor, which is invoked by writing <syntaxhighlight lang="Haskell" inline>{-# LANGUAGE CPP #-}</syntaxhighlight> at the top of the file. The accepted preprocessor directives align with those in standard C/C++.
 
Features of the preprocessor are encoded in [[source code]] as [[Directive (programming)|directives]] that start with <code>#</code>.
Line 44:
* <code>#pragma</code>
* <code>defined</code> (follows a conditional directive; not actually a directive, but rather an operator)
* <code>#__has_include</code> (operator)
* <code>#__has_cpp_attribute</code> (operator, C++ only)
* <code>#__has_embed__has_c_attribute</code> (operator, C only)
* <code>__has_embed</code> (operator)
{{div col end}}
 
Until [[C++26]], the C++ keywords <code>import</code>, <code>export</code>, and <code>module</code> were partially handled by the preprocessor as well.
 
The Haskell programming language also accepts C preprocessor directives, which is invoked by writing <syntaxhighlight lang="Haskell" inline>{-# LANGUAGE CPP #-}</syntaxhighlight> at the top of the file. The accepted preprocessor directives align with those in standard C/C++.
Haskell also accepts C preprocessor directives.
 
=== C# ===
Line 94 ⟶ 95:
The preprocessor was introduced to C around 1973 at the urging of Alan Snyder and also in recognition of the usefulness of the file inclusion mechanisms available in [[BCPL]] and [[PL/I]]. The first version offered file inclusion via <code>#include</code> and parameterless string replacement macros via <code>#define</code>. It was extended shortly after, firstly by [[Mike Lesk]] and then by John Reiser, to add arguments to macros and to support [[conditional compilation]].<ref>{{harvtxt|Ritchie|1993}}</ref>
 
The C preprocessor was part of a long macro-language tradition at Bell Labs, which was started by Douglas Eastwood and [[Douglas McIlroy]] in 1959.<ref name="BellSAP">{{cite encyclopedia |title=Bell SAP – SAP with conditional and recursive macros |encyclopedia=HOPL: Online Historical Encyclopaedia of Programming Languages |url=https://hopl.info/showlanguage.prx?exp=5635 |access-date=4 October 2020 |archive-date=14 October 2023 |archive-url=https://web.archive.org/web/20231014100551/https://hopl.info/showlanguage.prx?exp=5635 |url-status=dead }}</ref>
 
== Phases ==
Line 132 ⟶ 133:
 
==== Binary resource inclusion ====
[[C23 (C standard revision)|C23]] and [[C++26]] introduce the <code>#embed</code> directive for '''binary resource inclusion''' which allows including the content of a binary file into a source even thoughif it's is not valid C code.<ref>{{cite web |title=WG14-N3017 : #embed – a scannable, tooling-friendly binary resource inclusion mechanism |url=https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3017.htm |website=open-std.org |archive-url=https://web.archive.org/web/20221224045304/https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3017.htm |archive-date=24 December 2022 |date=2022-06-27 |url-status=live}}</ref><ref>{{Cite web|title=#embed - a scannable, tooling-friendly binary resource inclusion mechanism|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1967r14.html|website=open-std.org }}</ref>
This allows binary resources (like images) to be included into a program without requiring processing by external tools like <code>xxd -i</code> and without the use of [[string literal]]s which have a length limit on [[MSVC]]. Similarly to <code>xxd -i</code> the directive is replaced by a comma separated list of integers corresponding to the data of the specified resource. More precisely, if an array of type {{code|unsigned char}} is initialized using an <code>#embed</code> directive, the result is the same as-if the resource was written to the array using <code>[[fread]]</code> (unless a parameter changes the embed element width to something other than <code>[[Limits.h|CHAR_BIT]]</code>). Apart from the convenience, <code>#embed</code> is also easier <!--than what?--> for compilers to handle, since they are allowed to skip expanding the directive to its full form due to the [[as-if rule]].
 
Line 138 ⟶ 139:
 
<syntaxhighlight lang="cpp">
const unsigned char icon_display_dataiconDisplayData[] = {
#embed "art.png"
};
 
/* specify any type which can be initialized form integer constant expressions will do */
const char reset_blobresetBlob[] = {
#embed "data.bin"
};
 
/* attributes work just as well */
const signed char aligned_data_stralignedDataString[] __attribute__ ((aligned (8))) = {
#embed "attributes.xml"
};
Line 255 ⟶ 256:
One little-known usage pattern of the C preprocessor is known as [[X Macro|X-Macros]].<ref name="X_macros">[http://liw.iki.fi/liw/texts/cpp-trick.html Wirzenius, Lars. C "Preprocessor Trick For Implementing Similar Data Types". Retrieved January 9, 2011]</ref><ref>{{cite journal | last = Meyers | first = Randy |date=May 2001 | title = The New C: X Macros | journal = Dr. Dobb's Journal | url = http://www.ddj.com/cpp/184401387 | access-date = 1 May 2008 }}</ref><ref>{{cite journal | last = Beal | first = Stephan |date=August 2004 | title = Supermacros | url = http://wanderinghorse.net/computing/papers/#supermacros | access-date = 27 October 2008 }}</ref> An X-Macro is a [[header file]]. Commonly, these use the extension <code>.def</code> instead of the traditional <code>.h</code> . This file contains a list of similar macro calls, which can be referred to as "component macros." The include file is then referenced repeatedly.
 
Many compilers define additional, non-standard macros. A common reference for these macros is the [httphttps://predef.sourceforge.net/ Pre-defined C/C++ Compiler Macros project], which lists "various pre-defined compiler macros that can be used to identify standards, compilers, operating systems, hardware architectures, and even basic run-time libraries at compile-time."
 
Most compilers targeting [[Microsoft Windows]] implicitly define <code>_WIN32</code>.<ref>[http://msdn.microsoft.com/en-us/library/b0084kay.aspx List of predefined ANSI C and Microsoft C++ implementation macros.]</ref> This allows code, including preprocessor commands, to compile only when targeting Windows systems. A few compilers define <code>WIN32</code> instead. For such compilers that do not implicitly define the <code>_WIN32</code> macro, it can be specified on the compiler's command line, using <code>-D_WIN32</code>.
Line 345 ⟶ 346:
==Non-standard features ==
 
=== Pragma<code>#pragma</code> ===
The <code>#pragma</code> directive is defined by standard languages, but with little or no requirements for syntax after its name so that compilers are free to define subsequent syntax and associated behavior. For instance, a pragma is often used to allow suppression of error messages, manage heap and stack debugging and so on.
 
C99 introduced a few standard pragmas, taking the form <code>#pragma STDC ...</code>, which are used to control the floating-point implementation. The alternative, macro-like form {{code|_Pragma(...)}} was also added.
 
One of the most popular uses of the <code>#pragma</code> directive is [[pragma once|{{mono|#pragma once}}]], which behaves the same way an [[include guard|{{mono|#include}} guard]] would, condensed into a single directive placed at the top of the file. Despite being non-standard, it is supported by most compilers.
 
=== Trigraphs ===
Line 356 ⟶ 359:
Some [[Unix]] preprocessors provided an [[assertion (computing)|assertion]] feature {{endash}} which has little similarity to standard library assertions.<ref>[https://gcc.gnu.org/onlinedocs/cpp/Obsolete-Features.html GCC Obsolete features]</ref>
 
=== Include next<code>#include_next</code> ===
GCC provides <code>#include_next</code> for chaining headers of the same name.<ref>{{Cite web|url=https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html|title = Wrapper Headers (The C Preprocessor)}}</ref>
 
=== Import<code>#import</code> ===
Unlike C and C++, Objective-C includes an <code>#import</code> directive that is like <code>#include</code> but results in a file being included only once {{endash}} eliminating the need for include guards and [[pragma once|<code>#pragma once</code>]].
 
Line 367 ⟶ 370:
</syntaxhighlight>
 
In [[Microsoft Visual C++]] (MSVC), there also exists an <code>#import</code> preprocessor directive, used to import type libraries.<ref>{{Cite web|title=#import directive (C++)|url=https://learn.microsoft.com/en-us/cpp/preprocessor/hash-import-directive-cpp|title publisher= #import directive (C++)learn.microsoft.com}}</ref> It is a nonstandard directive.
 
<syntaxhighlight lang="cpp">
Line 373 ⟶ 376:
</syntaxhighlight>
 
The Objective-C directive should not be confused with the C++ keyword <code>import</code>, which is used to import C++ [[Precompiled header#Modules (C++)|modules]] (since [[C++20]]), and is not a preprocessor directive.
 
=== NullableNull directive ===
The null directive, which consists only of the <code>#</code> character, alone on a single line, is a non-standard directive in Microsoft Visual C++. It has no effect.<ref>{{Cite web|title=Null directive|url=https://learn.microsoft.com/en-us/cpp/preprocessor/null-directive|publisher=learn.microsoft.com}}</ref>
 
=== <code>#nullable</code> ===
The <code>#nullable</code> directive in C# is used to enable and disable nullable reference types. To enable them, use <code>#nullable enable</code>, and <code>#nullable disable</code> to disable them.
 
Line 391 ⟶ 397:
This directive does not exist in C/C++.
 
=== Region<code>#region</code> ===
The <code>#region</code> and <code>#endregion</code> directives in C# are used to expand/collapse sections of code in IDEs, and has no effect on actual compilation of the program. It is primarily used for code organisation and readability.
<syntaxhighlight lang="csharp">
#region Helper Methodsmethods
 
void Log(string message)
Line 404 ⟶ 410:
</syntaxhighlight>
 
While this directive does not exist in C/C++, MSVC and Visual Studio instead have <code>#pragma region</code> and <code>#pragma endregion</code>.<ref>{{Cite web|url= https://learn.microsoft.com/en-us/cpp/preprocessor/region-endregion|title = region and endregion pragma}}</ref> Thus the equivalent C++ code would be:
This directive does not exist in C/C++.
 
<syntaxhighlight lang="c++">
#pragma region Helper methods
 
void log(std::string_view message) {
std::println(message);
}
 
#pragma endregion
</syntaxhighlight>
 
=== <code>#using</code> ===
[[C++/CLI]] has the <code>#using</code> directive, which is used to import metadata into a program from a Microsoft Intermediate Language file (such as a {{mono|.dll}} file).<ref>{{Cite web|title=#using directive (C++/CLI)|url=https://learn.microsoft.com/en-us/cpp/preprocessor/hash-using-directive-cpp|publisher=learn.microsoft.com|date=29 June 2022}}</ref>
 
<syntaxhighlight lang="c++">
#using <MyComponent.dll>
#using "AssemblyA.dll"
#using "AssemblyB.dll"
 
using namespace System;
 
public ref class B {
public void Test(A a) {
// ...
}
};
 
int main(array<String^>^ args) {
A a;
B b;
B.Test(a);
}
</syntaxhighlight>
 
== Other uses ==
Line 424 ⟶ 463:
|page = 4
|work = safety of macros
}}</ref><ref name="processor">
{{cite journal
|author1=Michael D. Ernst |author2=[[Greg J. Badros]] |author3=David Notkin
|title = An Empirical Analysis of C Preprocessor Use
|author1title=MichaelAn D.empirical Ernstanalysis |author2=[[Gregof J.c Badros]]preprocessor use |author3journal=DavidIEEE Transactions on Software NotkinEngineering |url = http://dl.acm.org/citation.cfm?id=631305
|date = December 2002
|volume=28 |issue=12 |pages=1146–1170 |doi=10.1109/TSE.2002.1158288 |bibcode=2002ITSEn..28.1146E |url-access=subscription }}</ref>
|journal = C Preprocessor, Macros
|volume=28 |issue=12 |pages=1146–1170 |doi=10.1109/TSE.2002.1158288 |url-access=subscription }}</ref>
 
;Hidden multiple evaluation
Line 469 ⟶ 508:
 
;Import
The include directive limits code structure since it only allows including the content of one file into another. More modern languages support a [[modular programming|module]] concept that has public symbols that other modules import {{endash}} instead of including file content. Many contend that resulting code has reduced boilerplate and is easier to maintain since there is only one file for a module; not both a header and a body. [[C++20]] adds [[Precompiled header#Modules (C++)|modules]], and an <code>import</code> statement that is not handled via preprocessing.<ref>{{cite web|url=https://isocpp.org/files/papers/n4720.pdf|title=N4720: Working Draft, Extensions to C++ for Modules|archive-date=2019-04-30|archive-url=https://web.archive.org/web/20190430095053/https://isocpp.org/files/papers/n4720.pdf|url-status=live}}</ref><ref>{{cite web|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1857r1.html|title=P1857R1 – Modules Dependency Discovery}}
</ref> Modules in C++ compile faster and link faster than traditional headers,<ref>{{cite web|url=https://learn.microsoft.com/en-us/cpp/build/compare-inclusion-methods?view=msvc-170|title=Overview of modules in C++|date=12 February 2022 |publisher=Microsoft}}</ref> and eliminate the necessity of [[include guard|{{mono|#include}} guards]] or [[pragma once|{{mono|#pragma once}}]]. Until C++26, <code>import</code>, <code>export</code>, and <code>module</code> keywords were partially handled by the preprocessor.
 
For code bases that cannot migrate to modules immediately, C++ also offers "header units" as a feature, which allows header files to be imported in the same way a module would. Unlike modules, header units may emit macros, offering minimal breakage between migration. Header units are designed to be a transitional solution before totally migrating to modules.<ref>{{cite web|url=https://learn.microsoft.com/en-us/cpp/build/walkthrough-header-units?view=msvc-170|title=Walkthrough: Build and import header units in Microsoft Visual C++|date=12 April 2022 |publisher=Microsoft}}</ref> For instance, one may write <syntaxhighlight lang="C++" inline>import <string>;</syntaxhighlight> instead of <syntaxhighlight lang="C++" inline>#include <string></syntaxhighlight>, or <syntaxhighlight lang="C++" inline>import "MyHeader.hpp";</syntaxhighlight> instead of <syntaxhighlight lang="C++" inline>#include "MyHeader.hpp"</syntaxhighlight>. MostParadoxically, most build systems, such as [[CMake]], do not currently support this feature.
 
== See also ==
Line 494 ⟶ 533:
* [https://gcc.gnu.org/onlinedocs/cpp/index.html GNU CPP online manual]
* [http://msdn.microsoft.com/en-us/library/y4skk93w(VS.80).aspx Visual Studio .NET preprocessor reference]
* [httphttps://predef.sourceforge.net/ Pre-defined C/C++ Compiler Macros project]: lists "various pre-defined compiler macros that can be used to identify standards, compilers, operating systems, hardware architectures, and even basic run-time libraries at compile-time"
 
{{CProLang}}