2008-10-27 8 views
40

Tôi đang tìm cách chuyển đổi mã thông báo tiền xử lý thành chuỗi.Chuyển đổi mã thông báo tiền xử lý thành chuỗi

Cụ thể, tôi đã ở đâu đó có:

#define MAX_LEN 16 

và tôi muốn sử dụng nó để ngăn chặn đệm tràn ngập:

char val[MAX_LEN+1]; // room for \0 
sscanf(buf, "%"MAX_LEN"s", val); 

Tôi mở cửa cho những cách khác để thực hiện được điều tương tự, nhưng chỉ có thư viện chuẩn.

+0

http://stackoverflow.com/questions/195975/how-to-make-a-char-string-from-ac-macros-value –

+0

Bản sao có thể có của [C Macro để tạo chuỗi] (http: // stackoverflow.com/questions/798221/c-macros-to-create-strings) – rjstelling

Trả lời

78

http://www.decompile.com/cpp/faq/file_and_line_error_string.htm đặc biệt xem:

#define STRINGIFY(x) #x 
#define TOSTRING(x) STRINGIFY(x) 
#define AT __FILE__ ":" TOSTRING(__LINE__) 

để vấn đề của bạn có thể được giải quyết bằng cách làm sscanf(buf, "%" TOSTRING(MAX_LEN) "s", val);

+0

tại sao ghép 2 macro? Sẽ không đủ TOSTRING? –

+0

Xem câu trả lời bên dưới về việc mở rộng chuỗi kép. Bộ tiền xử lý C/C++ là dơ bẩn và xấu xí và tôi tin rằng không có tiêu chuẩn. Vì vậy, tại sao nó đòi hỏi hai thay vì một tôi không thể nói, bởi vì tôi không muốn làm nghiên cứu. – Dan

+2

@Daniel Brunner Một macro duy nhất sẽ dán mã thông báo, cho phép ''% "" MAX_LEN ""% "' một macro thứ hai làm cho giá trị * dấu * được dán, ví dụ: '" 16 "' bởi vì 'TOSTRING 'macro làm cho mã cuối cùng tương đương với' STRINGIFY (16) '. –

19

Tôi tìm thấy câu trả lời trực tuyến.

#define VERSION_MAJOR 4 
#define VERSION_MINOR 47 

#define VERSION_STRING "v" #VERSION_MAJOR "." #VERSION_MINOR 

ở trên không hoạt động nhưng hy vọng minh họa những gì tôi muốn làm, ví dụ: làm VERSION_STRING kết thúc như "v4.47".

Để tạo số hình thức sử dụng một cái gì đó phù hợp như

#define VERSION_MAJOR 4 
#define VERSION_MINOR 47 

#define STRINGIZE2(s) #s 
#define STRINGIZE(s) STRINGIZE2(s) 
#define VERSION_STRING "v" STRINGIZE(VERSION_MAJOR) \ 
"." STRINGIZE(VERSION_MINOR) 

#include <stdio.h> 
int main() { 
    printf ("%s\n", VERSION_STRING); 
    return 0; 
} 
+5

"STRINGIZE" âm thanh khủng khiếp .. – Blindy

4

Nó được một thời gian, nhưng điều này sẽ làm việc:

sscanf(buf, "%" #MAX_LEN "s", val); 

Nếu không, nó sẽ cần phải mẹo "mở rộng gấp đôi":

#define STR1(x) #x 
#define STR(x) STR1(x) 
sscanf(buf, "%" STR(MAX_LEN) "s", val); 
+1

Đầu tiên sẽ không hoạt động; # stringizes đối số macro trong macro mở rộng. Cái thứ hai sẽ hoạt động. –

2

Bạn nên sử dụng kích đúp mở rộng stringification vĩ mô trick. Hoặc chỉ cần có

#define MAX_LEN 16 
#define MAX_LEN_S "16" 

char val[MAX_LEN+1]; 
sscanf(buf, "%"MAX_LEN_S"s", val); 

và giữ nó đồng bộ. (Đó là một chút phiền toái, nhưng miễn là các định nghĩa nằm ngay cạnh nhau, bạn có thể sẽ nhớ.)

Thực ra, trong trường hợp này, sẽ không strncpy đủ?

strncpy(val, buf, MAX_LEN); 
val[MAX_LEN] = '\0'; 

Nếu nó là printf, tuy nhiên, điều này sẽ được dễ dàng hơn:

sprintf(buf, "%.*s", MAX_LEN, val); 
+1

Vâng, tôi muốn biểu tượng * hoặc một biểu tượng khác có sẵn cho các quy trình quét scanf giới hạn độ dài với một đối số. sprintf trong biểu mẫu đó hoạt động tốt hơn strncpy, imo, vì strncpy sẽ không chấm dứt chuỗi nếu nó vượt quá bộ đệm và ghi thêm dữ liệu nếu chuỗi quá ngắn. – davenpcj

1

Trong khi một số "tác phẩm" trên, cá nhân tôi khuyên bạn nên chỉ sử dụng một chuỗi API đơn giản thay vì dreck có trong libc. Có một số API di động, một số trong đó cũng được tối ưu hóa để dễ dàng đưa vào dự án của bạn ... và một số như ustr có chi phí không gian nhỏ và hỗ trợ cho các biến ngăn xếp.