编译时评估

发布于 2024-11-18 09:38:14 字数 1006 浏览 4 评论 0原文

如果我写,

enum chars = digits ~ uppercase;

字符串会在编译时连接吗?我假设会的。如果我用字符串文字或 CTFE 函数替换它,我无法测量任何显着的性能差异(即使调用它一亿次)。如果我用 const 替换 enum 确实会有所不同。有人告诉我这样写效率很低。我认为这很方便,而且我没有看到效率低下的情况。 (顺便说一句,该行位于递归调用的函数中)。

完整代码(转换为具有不同基数的数字系统)

import std.string;

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    static string sign;
    if (n < 0) {
        n *= -1;
        sign = "-";
    }
    enum chars = digits ~ uppercase;
    size_t r = cast(size_t)(n % b);
    if (n == r) {
        return sign ~ chars[r];
    }
    return toBase((n - r) / b, b) ~ chars[r];
}

编辑:更新的代码,响应评论,与问题无关

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    enum chars = digits ~ uppercase;
    long r = n % b;
    char c = chars[cast(size_t) abs(r)];
    if (n == r) {
        return (n < 0 ? "-" : "") ~ c;
    }
    return toBase((n - r) / b, b) ~ c;
}

If I write

enum chars = digits ~ uppercase;

will the string be concatenated at compile time? I'm assuming it will. If I replace it with a string literal or a CTFE function I can't measure any significant performance differences (even calling it a hundred million times). I do get a difference if I replace enum with const. I've been told it's inefficient to write it like this. I thought it was kind of convenient and I don't see the inefficiency. (BTW, the line is in a function that's called recursively).

The full code (converting to a numeral system with a different base)

import std.string;

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    static string sign;
    if (n < 0) {
        n *= -1;
        sign = "-";
    }
    enum chars = digits ~ uppercase;
    size_t r = cast(size_t)(n % b);
    if (n == r) {
        return sign ~ chars[r];
    }
    return toBase((n - r) / b, b) ~ chars[r];
}

Edit: updated code, in response to comments, not relevant to the question

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    enum chars = digits ~ uppercase;
    long r = n % b;
    char c = chars[cast(size_t) abs(r)];
    if (n == r) {
        return (n < 0 ? "-" : "") ~ c;
    }
    return toBase((n - r) / b, b) ~ c;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

意犹 2024-11-25 09:38:14

像这样的enum实例化总是在编译时求值(并且当编译时不可能求值时抛出编译错误),

因此串联是在编译时完成的,并且不可变版本存储在代码中并在运行时引用

enum instantiations like that are always evaluated at compile-time (and throw compile errors when the evaluation is impossible at compile time)

so the concatenation is done at compile-time and an immutable version is stored in the code and referenced at runtime

回忆那么伤 2024-11-25 09:38:14

自行检查字符串是否在编译时连接的一种方法是编译代码并检查目标文件。假设您的文件名为 test.d:

dmd -c test.d
objdump test.o | grep -C3 "012345"

...应该生成类似以下内容的内容:(

Contents of section .rodata:
 0000 2d000000 00000000 00000000 00000000  -...............
 0010 01000000 00000000 00000000 00000000  ................
 0020 30313233 34353637 38394142 43444546  0123456789ABCDEF
 0030 4748494a 4b4c4d4e 4f505152 53545556  GHIJKLMNOPQRSTUV
 0040 5758595a 00000000 00000000 00000000  WXYZ............
 0050 24000000 00000000 20000000 00000000  $....... .......

这是在 Linux 上;在其他平台上,您需要不同的工具来检查目标文件。)

如果您更改将 enum 转换为 conststring,您(可能)不会得到任何输出:grep 不会有连接字符串代码> 来查找。

但即使不使用 enum ,编译器也可能在编译时连接字符串。考虑这个程序:

 import std.stdio;

 enum a = "Aaaa";
 enum b = "Bbbb";
 enum c = "Cccc";

 void main() 
 {
   enum   x = a ~ b;
   const  y = b ~ a;
   string z = a ~ c;
   writeln(x, y, z);
 }

现在,编译它,并检查目标文件:

% dmd -c test2.d && objdump -s test2.o | egrep "(Aaaa|Bbbb)"
 0000 42626262 41616161 00000000 00000000  BbbbAaaa........
 0020 41616161 43636363 00000000 00000000  AaaaCccc........
 0040 41616161 42626262 00000000 00000000  AaaaBbbb........

我们看到 xyz 都是静态文字。 (将 abc 标记为 const 而不是 enum,并且您可能会看到不同的行为。)因此,虽然 enum 是编译时评估的保证,但缺少 enum 并不会阻止编译时评估。

One way to check for yourself whether the string is concatenated at compile time is to compile the code and examine the object file. Assuming your file is called test.d:

dmd -c test.d
objdump test.o | grep -C3 "012345"

...should produce something like:

Contents of section .rodata:
 0000 2d000000 00000000 00000000 00000000  -...............
 0010 01000000 00000000 00000000 00000000  ................
 0020 30313233 34353637 38394142 43444546  0123456789ABCDEF
 0030 4748494a 4b4c4d4e 4f505152 53545556  GHIJKLMNOPQRSTUV
 0040 5758595a 00000000 00000000 00000000  WXYZ............
 0050 24000000 00000000 20000000 00000000  $....... .......

(This is on Linux; on other platforms, you'll need different tools to inspect the object file.)

If you change your enum to const or string, you will (probably) get no output: there will be no concatenated string for grep to find.

But the compiler may concatenate strings at compile-time even when enum is not used. Consider this program:

 import std.stdio;

 enum a = "Aaaa";
 enum b = "Bbbb";
 enum c = "Cccc";

 void main() 
 {
   enum   x = a ~ b;
   const  y = b ~ a;
   string z = a ~ c;
   writeln(x, y, z);
 }

Now, compile it, and examine the object file:

% dmd -c test2.d && objdump -s test2.o | egrep "(Aaaa|Bbbb)"
 0000 42626262 41616161 00000000 00000000  BbbbAaaa........
 0020 41616161 43636363 00000000 00000000  AaaaCccc........
 0040 41616161 42626262 00000000 00000000  AaaaBbbb........

We see that x, y and z are all static literals. (Mark a, b and c as const instead of enum, and you may see different behaviour.) So, while enum is a guarantee of compile-time evaluation, the absence of enum doesn't prevent compile-time evaluation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文