2011-07-03 27 views
12

Nếu tôi viếtCompile thời gian thẩm định

enum chars = digits ~ uppercase; 

chuỗi sẽ được nối tại thời gian biên dịch? Tôi giả định nó sẽ. Nếu tôi thay thế nó bằng một hàm chuỗi hoặc hàm CTFE, tôi không thể đo được bất kỳ sự khác biệt đáng kể nào về hiệu suất (thậm chí gọi nó là một trăm triệu lần). Tôi nhận được một sự khác biệt nếu tôi thay thế enum bằng const. Tôi đã nói với nó là không hiệu quả để viết nó như thế này. Tôi nghĩ nó thuận tiện và tôi không thấy sự thiếu hiệu quả. (BTW, dòng nằm trong một hàm được gọi là đệ quy).

Mã đầy đủ (chuyển đổi sang một hệ thống chữ số với một cơ sở khác nhau)

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: cập nhật mã, để đáp ứng với ý kiến, không liên quan đến câu hỏi

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; 
} 
+2

bạn quên đặt lại chuỗi ký hiệu (bạn có thể sử dụng 'scope (exit) sign =" ";' cho điều đó) để 'toBase (-10,10)' theo sau là 'toBase (10,10)' sẽ cho cùng một kết quả –

+0

Đúng. Ha ha ha, lần đầu tiên tôi sử dụng một biến tĩnh. Khôn lanh. Đó là phạm vi (thoát) điều thực sự hữu ích phải không? Tôi hơi ngạc nhiên khi một cuộc gọi đệ quy không đủ điều kiện để thoát khỏi phạm vi. – fwend

+1

phạm vi (thoát) được thực hiện khi khung ngăn xếp hiện tại được bật lên ngăn xếp (như thử ... cuối cùng thực sự nhưng không có thêm thụt đầu dòng) đệ quy không làm điều đó –

Trả lời

9

enum instantiations như được luôn luôn được đánh giá tại thời gian biên dịch (và ném lỗi biên dịch khi đánh giá là không thể trong thời gian biên dịch)

nên nối được thực hiện tại thời gian biên dịch và phiên bản bất biến được lưu trữ trong các mã và tham chiếu tại thời gian chạy

5

Một cách để kiểm tra cho chính mình cho dù các chuỗi được nối tại thời gian biên dịch là để biên dịch mã, kiểm tra việc tệp đối tượng. Giả sử tập tin của bạn được gọi test.d:

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

... nên sản xuất cái gì đó như:

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

(Đây là trên Linux; trên các nền tảng khác, bạn sẽ cần các công cụ khác nhau để kiểm tra các tập tin đối tượng .)

Nếu bạn thay đổi enum thành const hoặc string, bạn sẽ (có thể) không có đầu ra: sẽ không có chuỗi nối cho grep để tìm.

Nhưng trình biên dịch có thể nối chuỗi tại thời điểm biên dịch ngay cả khi không sử dụng enum. Hãy xem xét chương trình này:

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); 
} 

Bây giờ, biên dịch nó, và kiểm tra các tập tin đối tượng:

% 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........ 

Chúng ta thấy rằng x, yz đều literals tĩnh. (Mark a, bcconst thay vì enum và bạn có thể thấy hành vi khác.) Vì vậy, trong khi enum là đảm bảo đánh giá thời gian biên dịch, sự vắng mặt của enum không ngăn việc đánh giá thời gian biên dịch.

Các vấn đề liên quan