Pragmas are a way of interacting with the compiler. They can be for providing special information to the compiler as well as getting information from it. Although they are useful in non-templated code as well, pragma(msg) can be helpful when debugging templates.
尽管它们在非模板化代码中也很有用,
pragma(msg)在调试模板时也很有用。
Every compiler vendor is free to introduce their special pragma directives in addition to the following mandatory ones:
65.1 pragma(msg)
Prints a message to stderr during compilation. No message is printed during the execution of the compiled program.
在编译期间向
stderr打印一条消息。编译后的程序在执行期间不会打印任何消息。
For example, the following pragma(msg) is being used for exposing the types of template parameters, presumably during debugging:
import std.string;
void func(A, B)(A a, B b) {
pragma(msg, format("Called with types '%s' and '%s'",
A.stringof, B.stringof));
// ...
}
void main() {
func(42, 1.5);
func("hello", 'a');
}
Called with types 'int' and 'double'
Called with types 'string' and 'char'
65.2 pragma(lib)
Instructs the compiler to link the program with a particular library. This is the easiest way of linking the program with a library that is already installed on the system.
指示编译器将程序与特定的库链接。这是将程序与系统上已经安装的库链接的最简单方法。
For example, the following program would be linked with the curl library without needing to mention the library on the command line:
import std.stdio;
import std.net.curl;
pragma(lib, "curl");
void main() {
// Get this chapter
writeln(get("ddili.org/ders/d.en/pragma.html"));
}
65.3 pragma(inline)
Specifies whether a function should be inlined or not.
指定函数是否应该内联。
Every function call has some performance cost. Function calls involve passing arguments to the function, returning its return value to the caller, and handling some bookkeeping information to remember where the function was called from so that the execution can continue after the function returns.
This cost is usually insignificant compared to the cost of actual work that the caller and the callee perform. However, in some cases just the act of calling a certain function can have a measurable effect on the program's performance. This can happen especially when the function body is relatively fast and when it is called from a short loop that repeats many times.
与调用方和被调用方执行的实际工作成本相比,这个成本通常是微不足道的。然而,在某些情况下,仅仅调用某个函数的行为就会对程序的性能产生可衡量的影响。这种情况尤其在函数体相对较快以及从重复多次的短循环中调用时发生。
The following program calls a small function from a loop and increments a counter when the returned value satisfies a condition:
import std.stdio;
import std.datetime.stopwatch;
// A function with a fast body:
ubyte compute(ubyte i) {
return cast(ubyte)(i * 42);
}
void main() {
size_t counter = 0;
StopWatch sw;
sw.start();
// A short loop that repeats many times:
foreach (i; 0 .. 100_000_000) {
const number = cast(ubyte)i;
if (compute(number) == number) {
++counter;
}
}
sw.stop();
writefln("%s milliseconds", sw.peek.total!"msecs");
}
The code takes advantage of std.datetime.stopwatch.StopWatch to measure the time it takes executing the entire loop:
674 milliseconds
The -inline compiler switch instructs the compiler to perform a compiler optimization called function inlining:
$ dmd deneme.d -w -inline
When a function is inlined, its body is injected into code right where it is called from; no actual function call happens. The following is the equivalent code that the compiler would compile after inlining:
当一个函数被内联时,它的函数体被注入到调用它的代码中;没有实际的函数调用发生。下面是内联后编译器将编译的等价代码。
// An equivalent of the loop when compute() is inlined:
foreach (i; 0 .. 100_000_000) {
const number = cast(ubyte)i;
const result = cast(ubyte)(number * 42);
if (result == number) {
++counter;
}
}
On the platform that I tested that program, eliminating the function call reduced the execution time by about 40%:
407 milliseconds
Although function inlining looks like a big gain, it cannot be applied for every function call because otherwise inlined bodies of functions would make code too large to fit in the CPU's instruction cache. Unfortunately, this can make the code even slower. For that reason, the decision of which function calls to inline is usually left to the compiler.
虽然函数内联看起来是一个很大的好处,但它不能应用于每个函数调用,因为否则内联函数体将使代码太大,无法放入CPU的指令缓存中。不幸的是,这可能会使代码变得更慢。因此,内联哪个函数调用通常由编译器决定。
However, there may be cases where it is beneficial to help the compiler with this decision. The inline pragma instructs the compiler in its inlining decisions:
在某些情况下,帮助编译器做出这个决定是有益的。内联语指示编译器进行内联决策。
pragma(inline, false): Instructs the compiler to never inline certain functions even when the-inlinecompiler switch is specified.pragma(inline, true): Instructs the compiler to definitely inline certain functions when the-inlinecompiler switch is specified. This causes a compilation error if the compiler cannot inline such a function. (The exact behavior of this pragma may be different on your compiler.)pragma(inline): Sets the inlining behavior back to the setting on the compiler command line: whether-inlineis specified or not.
pragma(inline, false):指示编译器永远不要内联某些函数,即使指定了-inline编译器开关。pragma(inline, true):指示编译器在指定-inline编译器开关时确定内联某些函数。如果编译器不能内联这样的函数,则会导致编译错误。pragma(inline):将内联行为设置回编译器命令行上的设置,无论-inline是否指定。
These pragmas can affect the function that they appear in, as well as they can be used with a scope or colon to affect more than one function:
pragma(inline, false) {
// Functions defined in this scope should not be inlined
// ...
}
int foo() {
pragma(inline, true); // This function should be inlined
// ...
}
pragma(inline, true):
// Functions defined in this section should be inlined
// ...
pragma(inline):
// Functions defined in this section should be inlined or not
// depending on the -inline compiler switch
// ...
Another compiler switch that can make programs run faster is -O, which instructs the compiler to perform more optimization algorithms. However, faster program speeds come at the expense of slower compilation speeds because these algorithms take significant amounts of time.
另一个可以使程序运行更快的编译器开关是
-O,它指示编译器执行更多的优化算法。然而,更快的程序速度是以较慢的编译速度为代价的,因为这些算法需要大量的时间。
65.4 pragma(startaddress)
Specifies the start address of the program. Since the start address is normally assigned by the D runtime environment, it is very unlikely that you will ever use this pragma.
指定程序的开始地址。由于起始地址通常是由D运行时环境分配的,因此您不太可能使用这个pragma。
65.5 pragma(mangle)
Specifies that a symbol should be name mangled differently from the default name mangling method. Name mangling is about how the linker identifies functions and their callers. This pragma is useful when D code needs to call a library function that happens to be a D keyword.
指定符号的名称mangling应与默认的名称mangling方法不同。名称混乱是关于链接器如何标识函数及其调用者。当D代码需要调用恰好是D关键字的库函数时,此pragma非常有用。
For example, if a C library had a function named override, because override happens to be a keyword in D, the only way of calling it from D would be through a different name. However, that different name must still be mangled as the actual function name in the library for the linker to be able to identify it:
/* If a C library had a function named 'override', it could
* only be called from D through a name like 'c_override',
* mangled as the actual function name: */
pragma(mangle, "override")
extern(C) string c_override(string);
void main() {
/* D code calls the function as c_override() but the
* linker would find it by its correct C library name
* 'override': */
auto s = c_override("hello");
}