2009-04-28 9 views
24

Titles Alternative (để hỗ trợ tìm kiếm)C Macros để tạo ra chuỗi

  • Chuyển đổi một mã thông báo tiền xử lý thành một chuỗi
  • Làm thế nào để tạo ra một chuỗi char từ giá trị của một C vĩ mô không?

Câu hỏi gốc

Tôi muốn sử dụng C#define để xây dựng chuỗi chữ tại thời gian biên dịch.

Chuỗi là lĩnh vực mà thay đổi cho gỡ lỗi, phát hành, vv

Tôi muốn một số một số điều như thế này:

#ifdef __TESTING 
    #define IV_DOMAIN domain.org   //in house testing 
#elif __LIVE_TESTING 
    #define IV_DOMAIN test.domain.com  //live testing servers 
#else 
    #define IV_DOMAIN domain.com   //production 
#endif 

// Sub-Domain 
#define IV_SECURE "secure.IV_DOMAIN"    //secure.domain.org etc 
#define IV_MOBILE "m.IV_DOMAIN" 

Nhưng tiền xử lý không đánh giá bất cứ điều gì trong ""

  1. Có cách nào khác không?
  2. Đây có phải là một ý tưởng hay không?
+0

Bản sao có thể có của [Chuyển đổi mã thông báo tiền xử lý thành chuỗi] (http://stackoverflow.com/questions/240353/convert-a-preprocessor -token-to-a-string) –

Trả lời

31

Trong C, chuỗi ký tự được nối tự động. Ví dụ:

const char * s1 = "foo" "bar"; 
const char * s2 = "foobar"; 

s1s2 là cùng một chuỗi.

Vì vậy, đối với vấn đề của bạn, câu trả lời (không dán token) là

#ifdef __TESTING 
    #define IV_DOMAIN "domain.org" 
#elif __LIVE_TESTING 
    #define IV_DOMAIN "test.domain.com" 
#else 
    #define IV_DOMAIN "domain.com" 
#endif 

#define IV_SECURE "secure." IV_DOMAIN 
#define IV_MOBILE "m." IV_DOMAIN 
6

Hãy thử sử dụng các nhà điều hành ##

#define IV_SECURE secure.##IV_DOMAIN 
+1

Điều này không giải quyết được sự cố "". – mouviciel

+0

Tôi nghĩ rằng OP đã hỏi về nối chuỗi (#), không dán mã thông báo (##). Tôi đã không downvote, mặc dù. Câu hỏi là một chút mơ hồ. –

+0

Dán mã thông báo ('##') hoặc xâu chuỗi ('#') sẽ không hoạt động nếu không có nhiều thứ bổ sung. –

8

Strings được tiếp theo với nhau được kết hợp bởi trình biên dịch C.

#define DOMAIN "example.com" 
#define SUBDOMAIN "test." DOMAIN 
const char *asCString = SUBDOMAIN; 
NSString *asNSString = @SUBDOMAIN; 
5

Điều bạn cần là các toán tử # và ## và nối chuỗi tự động.

Toán tử tiền xử lý # biến thông số macro thành chuỗi. Toán tử ## dán hai thẻ (chẳng hạn như tham số macro) với nhau.

Khả năng mà nói đến cái tâm với tôi là

#define IV_DOMAIN domain.org 
#define IV_SECURE(DOMAIN) "secure." #DOMAIN 

mà nên thay đổi IV_SECURE để

#define IV_SECURE "secure." "domain.org" 

mà sẽ tự động nối để "secure.domain.org" (giả sử các giai đoạn của dịch đều giống nhau trong C như C++).

CHỈNH SỬA KHÁC: Xin vui lòng, vui lòng đọc các nhận xét, cho thấy cách tôi đã nhầm lẫn. Ghi nhớ rằng tôi hoàn toàn có kinh nghiệm trong C, mặc dù có lẽ một liên lạc gỉ. Tôi sẽ xóa câu trả lời này, nhưng tôi nghĩ rằng tôi muốn để nó như là một ví dụ về cách dễ dàng bị nhầm lẫn bởi bộ tiền xử lý C.

+0

## không dán chuỗi, nó dán mã thông báo. Sự khác biệt tinh tế nhưng quan trọng. –

+0

Thật không may, phiên bản của cpp chạy trong hộp Cygwin của tôi không hiểu toán tử # khi bạn mô tả nó. – mouviciel

+0

Toán tử # chỉ hoạt động trên các tham số macro. I E. #define IV_SECURE (DOMAIN) "bảo mật". #DOMAIN Không có nhiều trợ giúp trong trường hợp này. –

3

Như những người khác đã lưu ý, sử dụng dán thẻ. Bạn cũng nên lưu ý rằng các tên macro như

__TESTING 

được đặt trước trong C (không biết về mục tiêu C) để triển khai - bạn không được phép sử dụng chúng trong mã của riêng bạn. Các tên được đặt trước là bất kỳ thứ gì có chứa dấu gạch dưới kép và bất kỳ thứ gì bắt đầu bằng dấu gạch dưới và chữ hoa.

+0

Mục tiêu C được coi là bộ siêu C nghiêm ngặt, và vì vậy đây phải là một thông báo hợp lệ. –

19

Có một vài cách để làm điều này:

  1. nếu bạn đang làm việc với xâu chỉ, bạn có thể chỉ đơn giản sử dụng chỉ cần sử dụng dây - đặt một chuỗi chữ cái khác làm cho trình biên dịch để ghép chúng .

  2. nếu có thể có những thứ khác ngoài chuỗi ký tự liên quan (ví dụ: bạn đang tạo số nhận dạng mới từ macro) sử dụng toán tử dán mã thông báo preprocessor '##'. Bạn có thể cũng cần phải sử dụng '#' 'stringizing điều hành để thực hiện các macro của bạn vào các chuỗi chữ

Một ví dụ về # 1:.

#ifdef __TESTING 
    #define IV_DOMAIN "domain.org"      //in house testing 
#elif __LIVE_TESTING 
    #define IV_DOMAIN "test.domain.com"   //live testing servers 
#else 
    #define IV_DOMAIN "domain.com"      //production 
#endif 

// Sub-Domain 
#define IV_SECURE "secure." IV_DOMAIN   //secure.domain.org etc 
#define IV_MOBILE "m." IV_DOMAIN 

Và như xa như các nhà điều hành dán thẻ đi, tôi không nghĩ rằng hầu hết các câu trả lời gợi ý ted bằng cách sử dụng các nhà điều hành tiền xử lý thẻ preprocessor đã thực sự thử nó - nó có thể được khôn lanh để sử dụng.

Sử dụng câu trả lời mà thường được gợi ý sẽ dẫn đến một lỗi biên dịch khi bạn cố gắng sử dụng IV_SECURE vĩ mô, bởi vì:

#define IV_SECURE "secure."##IV_DOMAIN 

mở rộng để:

"secure"domain.org 

Bạn có thể muốn thử để sử dụng toán tử ' # `'' stringizing ':

#define IV_SECURE "secure." #IV_DOMAIN 

Nhưng tha t sẽ không hoạt động vì nó chỉ hoạt động trên các đối số macro - không chỉ bất kỳ macro cũ nào.

một điều cần lưu ý khi bạn sử dụng toán tử tiền xử lý ('##') hoặc xâu chuỗi ('#') là bạn phải sử dụng thêm một mức không giới hạn để chúng hoạt động bình thường trong tất cả trường hợp.

Nếu bạn không làm điều này và các mặt hàng truyền cho các nhà điều hành mã thông báo dán là macro bản thân, bạn sẽ nhận được kết quả mà có lẽ không phải những gì bạn muốn:

#include <stdio.h> 

#define STRINGIFY2(x) #x 
#define STRINGIFY(x) STRINGIFY2(x) 
#define PASTE2(a, b) a##b 
#define PASTE(a, b) PASTE2(a, b) 

#define BAD_PASTE(x,y) x##y 
#define BAD_STRINGIFY(x) #x 

#define SOME_MACRO function_name 

int main() 
{ 
    printf("buggy results:\n"); 
    printf("%s\n", STRINGIFY(BAD_PASTE(SOME_MACRO, __LINE__))); 
    printf("%s\n", BAD_STRINGIFY(BAD_PASTE(SOME_MACRO, __LINE__))); 
    printf("%s\n", BAD_STRINGIFY(PASTE(SOME_MACRO, __LINE__))); 

    printf("\n" "desired result:\n"); 
    printf("%s\n", STRINGIFY(PASTE(SOME_MACRO, __LINE__))); 
} 

Sản lượng:

buggy results: 
SOME_MACRO__LINE__ 
BAD_PASTE(SOME_MACRO, __LINE__) 
PASTE(SOME_MACRO, __LINE__) 

desired result: 
function_name21 

Vì vậy, sử dụng ban đầu IV_DOMAIN định nghĩa của bạn và các macro utilty từ trên cao, bạn có thể làm điều này để có được những gì bạn muốn:

// Sub-Domain 
#define IV_SECURE "secure." STRINGIFY(IV_DOMAIN) //secure.domain.org etc 
#define IV_MOBILE "m." STRINGIFY(IV_DOMAIN) 
6

Tôi thấy nhiều câu trả lời đúng và chính xác cho câu hỏi đầu tiên của bạn, nhưng không có câu trả lời nào cho câu hỏi thứ hai của bạn, vì vậy đây là: Tôi nghĩ đây là một ý tưởng tồi tệ. Tại sao bạn phải xây dựng lại phần mềm của bạn (đặc biệt là phiên bản phát hành) chỉ để thay đổi tên máy chủ? Ngoài ra, làm thế nào bạn sẽ biết phiên bản phần mềm nào của bạn trỏ đến máy chủ nào? Bạn sẽ phải xây dựng trong một cơ chế để kiểm tra lúc chạy. Nếu nó hoàn toàn thực tế trên nền tảng của bạn, tôi khuyên bạn nên tải các tên miền/URL từ một tập tin cấu hình. Chỉ những nền tảng nhúng nhỏ nhất có thể không "thực tế" cho mục đích đó :)