2010-02-25 17 views
61

मुझे सी में ऐसा कुछ करना है। यह केवल तभी काम करता है जब मैं char का उपयोग करता हूं, लेकिन मुझे एक स्ट्रिंग की आवश्यकता होती है। मैं यह कैसे कर सकता हूँ?सी सशर्त प्रीप्रोसेसर-निर्देशों में तारों की तुलना कैसे करें

#define USER "jack" // jack or queen 

#if USER == "jack" 
#define USER_VS "queen" 
#elif USER == "queen" 
#define USER_VS "jack" 
#endif 
+0

आप स्ट्रैम्प का उपयोग क्यों नहीं कर सकते? –

+0

@ ब्रायन: हाँ, मैंने भी प्रश्न पढ़ा :-)। बस यह सुनिश्चित करना चाहता था कि वह स्ट्रैम्प मौजूद है, और प्रतिक्रिया प्रबुद्ध हो सकती है, क्योंकि मैं यह # डिफाईन सामान करने का कोई कारण नहीं सोच सकता। –

+2

बस यह उल्लेख करना चाहता था कि वही चीज नियमित कोड के लिए भी जाती है, न केवल पूर्वप्रचारक। एक साधारण मूल्य कब करेंगे जब स्ट्रिंग का उपयोग न करें। स्ट्रिंग्स में पूर्णांक या enums की तुलना में अधिक ओवरहेड होता है और यदि आपको उनकी तुलना करने से कुछ और करने की आवश्यकता नहीं है, तो तार गलत समाधान हैं। – swestrup

उत्तर

51

मुझे नहीं लगता कि प्रीप्रोसेसर निर्देशों में चर लंबाई लंबाई स्ट्रिंग तुलना करने का एक तरीका है। आप शायद निम्न कार्य कर सकते हैं हालांकि:

#define USER_JACK 1 
#define USER_QUEEN 2 

#define USER USER_JACK 

#if USER == USER_JACK 
#define USER_VS USER_QUEEN 
#elif USER == USER_QUEEN 
#define USER_VS USER_JACK 
#endif 

या आप कोड को थोड़ा सा प्रतिक्रिया दे सकते हैं और इसके बजाय सी कोड का उपयोग कर सकते हैं।

+2

या वह इस विशिष्ट मामले में 'USER_VS (3 - USER) को परिभाषित कर सकता है। :) –

5

तारों के बजाय संख्यात्मक मानों का उपयोग करें।

अंत में स्थिरांक जैक या क्वीन को स्ट्रिंग में परिवर्तित करने के लिए, स्ट्रिंग (और/या टोकननाइज़) ऑपरेटर का उपयोग करें।

0

अपने तार संकलन समय स्थिरांक हैं (आपके मामले में), तो आप निम्न चाल का उपयोग कर सकते हैं:

#define USER_JACK strcmp(USER, "jack") 
#define USER_QUEEN strcmp(USER, "queen") 
#if $USER_JACK == 0 
#define USER_VS USER_QUEEN 
#elif USER_QUEEN == 0 
#define USER_VS USER_JACK 
#endif 

संकलक पहले से strcmp का परिणाम बता सकते हैं और इसके परिणाम के साथ strcmp का स्थान ले लेगा , इस प्रकार आपको एक # डिफाईन दिया जाता है जिसे प्रीप्रोसेसर निर्देशों से तुलना की जा सकती है। मुझे नहीं पता कि कंपाइलर विकल्पों पर कंपाइलर्स/निर्भरता के बीच कोई अंतर है, लेकिन यह मेरे लिए जीसीसी 4.7.2 पर काम करता है।

संपादित करें: आगे की जांच पड़ताल करने पर, यह इस तरह दिखेगा एक toolchain विस्तार, नहीं जीसीसी विस्तार, तो ले कि ध्यान में ...

+6

यह निश्चित रूप से मानक सी नहीं है, और मुझे नहीं लगता कि यह किसी भी कंपाइलर के साथ कैसे काम करेगा। संकलक कभी-कभी अभिव्यक्ति के परिणामों को भी बता सकता है (यहां तक ​​कि फ़ंक्शन कॉल, यदि वे इनलाइन हैं), लेकिन प्री-प्रोसेसर नहीं। क्या आपका उपयोग '$' का कुछ प्रकार का प्री-प्रोसेसर एक्सटेंशन है? – ugoren

+2

ऐसा लगता है कि '#if $ USER_JACK == 0' वाक्यविन्यास काम करता है, कम से कम जीएनयू सी ++ देशी एंड्रॉइड कोड (जेएनआई) के निर्माण के लिए उपयोग किया जाता है ... मुझे यह नहीं पता था, लेकिन यह बहुत उपयोगी है, हमें बताने के लिए धन्यवाद इसके बारे में! – gregko

+6

मैंने जीसीसी 4.9.1 पर यह कोशिश की, और मुझे विश्वास नहीं है कि यह वही करेगा जो आपको लगता है। जबकि कोड संकलित होगा, यह आपको अपेक्षित परिणाम नहीं देगा। '$' को एक चर नाम के रूप में माना जाता है। तो प्रीप्रोसेसर '$ USER_JACK' चर की तलाश में है, इसे नहीं ढूंढ रहा है और इसे 0 का डिफ़ॉल्ट मान दे रहा है। इस प्रकार, आपके पास हमेशा यूएससीवीएस को यूएससीक्व्यूएन के रूप में परिभाषित किया जाएगा, भले ही strcmp – Vitali

19

[अपडेट 2016/01/31]

कुछ के रूप में नहीं किया है मेरे पहले के जवाब की तरह क्योंकि यह स्ट्रिंग तुलनाओं की आवश्यकता के बिना लक्ष्य को पूरा करके ओपी के पूरे compile time string compare पहलू से से बचा है, यहां एक और विस्तृत उत्तर दिया गया है।

आप नहीं कर सकते! सी 9 8 या सी 99 में नहीं। सी 11 में भी नहीं। मैक्रो मैनिपुलेशन की कोई मात्रा इसे बदल नहीं देगी।

की परिभाषा #if में प्रयुक्त स्ट्रिंग की अनुमति नहीं देती है।

इसलिए यदि आप अपने आप को वर्णों तक सीमित आप इस का उपयोग कर सकते यह वर्णों की अनुमति देता है:

#define JACK 'J' 
#define QUEEN 'Q' 

#define CHOICE JACK  // or QUEEN, your choice 

#if 'J' == CHOICE 
#define USER "jack" 
#define USER_VS "queen" 
#elif 'Q' == CHOICE 
#define USER "queen" 
#define USER_VS "jack" 
#else 
#define USER "anonymous1" 
#define USER_VS "anonymous2" 
#endif 

#pragma message "USER IS " USER 
#pragma message "USER_VS IS " USER_VS 

आप कर सकते हैं! सी ++ 11 में। यदि आप तुलना के लिए संकलन समय सहायक कार्य परिभाषित करते हैं।

// compares two strings in compile time constant fashion 
constexpr int c_strcmp(char const* lhs, char const* rhs) 
{ 
    return (('\0' == lhs[0]) && ('\0' == rhs[0])) ? 0 
     : (lhs[0] != rhs[0]) ? (lhs[0] - rhs[0]) 
     : c_strcmp(lhs+1, rhs+1); 
} 
// some compilers may require ((int)lhs[0] - (int)rhs[0]) 

#define JACK "jack" 
#define QUEEN "queen" 

#define USER JACK  // or QUEEN, your choice 

#if 0 == c_strcmp(USER, JACK) 
#define USER_VS QUEEN 
#elif 0 == c_strcmp(USER, QUEEN) 
#define USER_VS JACK 
#else 
#define USER_VS "unknown" 
#endif 

#pragma message "USER IS " USER 
#pragma message "USER_VS IS " USER_VS 

तो, अंत में, आप जिस तरह से आप USER और USER_VS के लिए अंतिम स्ट्रिंग मूल्यों को चुनने के अपने लक्ष्य accomlish बदलने के लिए होगा।

आप सी 99 में संकलन समय स्ट्रिंग तुलना नहीं कर सकते हैं, लेकिन आप स्ट्रिंग का चयन करने के समय संकलित कर सकते हैं।

यदि आपको वास्तव में तुलनात्मक समय की तुलना करने के लिए संकलित समय करना होगा, तो आपको उस सुविधा को अनुमति देने वाले C++ 11 या नए रूपों में बदलना होगा।

[मूल जवाब इस प्रकार है]

प्रयास करें:

#define jack_VS queen 
#define queen_VS jack 

#define USER jack   // jack or queen, your choice 
#define USER_VS USER##_VS // jack_VS or queen_VS 

// stringify usage: S(USER) or S(USER_VS) when you need the string form. 
#define S(U) S_(U) 
#define S_(U) #U 

अद्यतन: एएनएसआई टोकन चिपकाने कभी कभी स्पष्ट से कम है। ;- डी

एक मैक्रो से पहले एक # डालने से इसे अपने मूल्य की स्ट्रिंग में बदल दिया जाता है, इसके नंगे मूल्य के बजाय।

दो टोकन के बीच एक डबल ## डालने से उन्हें एक टोकन में संयोजित किया जाता है।

तो, मैक्रो USER_VS विस्तार jack_VS या queen_VS, तुम कैसे USER सेट के आधार पर है।

स्ट्रिंग मैक्रो S(...) मैक्रो इंडिकेशन का उपयोग करता है इसलिए नामित मैक्रो का मान स्ट्रिंग में परिवर्तित हो जाता है। मैक्रो के नाम के बजाय।

इस प्रकार USER##_VSjack_VS (या queen_VS) बन जाता है, इस पर निर्भर करता है कि आप USER कैसे सेट करते हैं।

बाद में, जब stringify मैक्रो (इस उदाहरण में jack_VS) S(USER_VS) रूप USER_VS का मूल्य प्रयोग किया जाता है अविवेक कदम S_(jack_VS) जो एक स्ट्रिंग "queen" में अपने मूल्य (queen) धर्मान्तरित करने के लिए पारित कर दिया है।

यदि आप USER से queen पर सेट करते हैं तो अंतिम परिणाम स्ट्रिंग "jack" है।

टोकन संयोजन के लिए देखें: https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html

टोकन स्ट्रिंग रूपांतरण के लिए, देखें: [। UPDATED 2015/02/15 लिखने में कोई त्रुटि को दूर करने के] https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification

+0

पर ध्यान दिए बिना हो सकता है कि अगर आपने समझाया कि बिल्ली में वास्तव में क्या कर रहा है यहां, आपको कुछ अपवॉट मिल सकते हैं। –

+0

@ आर्केनइंजिनर - अधिक जानकारी के लिंक के साथ, मेरे समाधान में उपयोग किए गए एएनएसआई टोकन विषमताओं के संक्षिप्त विवरण के साथ अपडेट किया गया। –

+1

बढ़िया है, लेकिन सवाल में अनुरोध के अनुसार आप संकलन समय पर स्ट्रिंग की तुलना कहां कर रहे हैं? अनुलेख मैक्रोज़ में 'strcmp' पहले से ही सुझाव दिया गया है लेकिन गैर-मानक-अनुरूप है। –

1

Patrick द्वारा answere और Jesse Chisholm द्वारा किए गए मैं निम्नलिखित करता हूं:

#define QUEEN 'Q' 
#define JACK 'J' 

#define CHECK_QUEEN(s) (s==QUEEN?1:0) 
#define CHECK_JACK(s) (s==JACK?1:0) 

#define USER 'Q' 

[... later on in code ...] 

#if CHECK_QUEEN(USER) 
    compile_queen_func(); 
#elif CHECK_JACK(USER) 
    compile_jack_func(); 
#elif 
#error "unknown user" 
#endif 

के बजाय#define USER QUEEN भी काम करना चाहिए लेकिन परीक्षण नहीं किया गया था भी काम करता है और इसे संभालना आसान हो सकता है।

1

जैसा कि पहले से ऊपर बताया गया है, आईएसओ-सी 11 प्रीप्रोसेसर समर्थन स्ट्रिंग तुलना नहीं करता है। हालांकि, "विपरीत मूल्य" के साथ मैक्रो असाइन करने की समस्या को "टोकन पेस्टिंग" और "टेबल एक्सेस" के साथ हल किया जा सकता है। जेसी का सरल संयोजक/स्ट्रिंगफाइफ़ मैक्रो-सॉल्यूशन जीसीसी 5.4.0 के साथ विफल रहता है क्योंकि स्ट्रिंगेशन से पहले समामेलन (आईएसओ सी 11 के अनुरूप) का मूल्यांकन किया जाता है।हालांकि, यह तय किया जा सकता है:

#define P_(user) user ## _VS 
#define VS(user) P_ (user) 
#define S(U) S_(U) 
#define S_(U) #U 

#define jack_VS queen 
#define queen_VS jack 

S (VS (jack)) 
S (jack) 
S (VS (queen)) 
S (queen) 

#define USER jack   // jack or queen, your choice 
#define USER_VS USER##_VS // jack_VS or queen_VS 
S (USER) 
S (USER_VS) 

पहली पंक्ति (मैक्रो P_()) अगली पंक्ति (मैक्रो VS()) से पहले stringization संयोजन खत्म जाने के लिए (Why do I need double layer of indirection for macros? देखें) एक अविवेक कहते हैं। स्ट्रिंगनाइज़ेशन मैक्रोज़ (S() और S_()) जेसी से हैं।

तालिका (मैक्रोज़ jack_VS और queen_VS) जो कि ओपी के निर्माण के बाद बनाए रखने के लिए बहुत आसान है, जेसी से है।

अंत में, अगले चार-पंक्ति ब्लॉक फ़ंक्शन-शैली मैक्रोज़ को आमंत्रित करता है। आखिरी चार-लाइन ब्लॉक जेसी के जवाब से है।

foo.c में कोड भंडारण और पूर्वप्रक्रमक लागू gcc -nostdinc -E foo.c पैदावार:

# 1 "foo.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "foo.c" 
# 9 "foo.c" 
"queen" 
"jack" 
"jack" 
"queen" 



"jack" 
"USER_VS" 

आउटपुट के रूप में की उम्मीद है। अंतिम पंक्ति से पता चलता है कि USER_VS मैक्रो स्ट्रिंग के पहले विस्तारित नहीं है।

-2

यह आसान है मैं तुम सिर्फ कह सकते हैं

#define NAME JACK  
#if NAME == queen 
1

बजना के साथ मेरे लिए काम किया निम्नलिखित में सोचते हैं। प्रतीकात्मक मैक्रो मूल्य तुलना के रूप में दिखाई देता है की अनुमति देता है। #error xxx यह देखने के लिए है कि संकलक वास्तव में क्या करता है। बिल्ली # परिभाषित बिल्ली (ए, बी) एक ## बी चीजों को तोड़ता है।

#define cat(a,...) cat_impl(a, __VA_ARGS__) 
#define cat_impl(a,...) a ## __VA_ARGS__ 

#define xUSER_jack 0 
#define xUSER_queen 1 
#define USER_VAL cat(xUSER_,USER) 

#define USER jack // jack or queen 

#if USER_VAL==xUSER_jack 
    #error USER=jack 
    #define USER_VS "queen" 
#elif USER_VAL==xUSER_queen 
    #error USER=queen 
    #define USER_VS "jack" 
#endif 
+0

सुनिश्चित नहीं है कि यह बुरा, शानदार, या दोनों था, लेकिन यह वही था जो मैं ढूंढ रहा था - धन्यवाद! एक और सहायक चाल है # अपने xUSER_ मैक्रोज़ को 1 से शुरू करना है। फिर आप अपने #elsif सूची के अंत में #else क्लॉज जोड़ सकते हैं ताकि उपयोगकर्ता उन मामलों को पकड़ सकें जहां USER है गलती से उस चीज़ पर सेट करें जिसे आप नहीं जानते हैं कि कैसे संभालना है। (अन्यथा यदि आप 0 से 0 तो 0 केस बीको आपके पकड़ने के लिए mes, क्योंकि यह पूर्व परिभाषित प्रतीक के लिए preprocessor के डिफ़ॉल्ट संख्यात्मक मान है।) – sclamage

संबंधित मुद्दे