मैं संकलन-समय पर एक # मूल्य का मूल्य कैसे दिखाऊं?


123

मैं यह जानने की कोशिश कर रहा हूं कि मेरे कोड के कौन से संस्करण का उपयोग करने के बारे में सोचता है। मैं कुछ इस तरह करना चाहता हूं:

#error BOOST_VERSION

लेकिन प्रीप्रोसेसर BOOST_VERSION का विस्तार नहीं करता है।

मुझे पता है कि मैं इसे प्रोग्राम से रन-टाइम पर प्रिंट कर सकता हूं, और मुझे पता है कि मैं उत्तर खोजने के लिए प्रीप्रोसेसर के आउटपुट को देख सकता हूं। मुझे लगता है कि संकलन के दौरान ऐसा करने का एक तरीका उपयोगी हो सकता है।


7
भविष्य के आगंतुकों के लिए ... क्रिस बैरी अंत में सामान्यीकृत समाधान प्रदान करता है (बूस्ट विशिष्ट सामान से रहित)।
jww

जवाबों:


117

मुझे पता है कि मूल प्रश्न के बाद यह एक लंबा समय है, लेकिन यह अभी भी उपयोगी हो सकता है।

यह जीसीसी में स्ट्रिंग ऑपरेटर "#" का उपयोग करके किया जा सकता है, लेकिन इसके लिए दो चरणों की आवश्यकता होती है।

#define XSTR(x) STR(x)
#define STR(x) #x

मैक्रो का मान तब प्रदर्शित किया जा सकता है:

#pragma message "The value of ABC: " XSTR(ABC)

देखें: 3.4 जीसीसी ऑनलाइन प्रलेखन में स्ट्रिंग।

यह काम किस प्रकार करता है:

प्रीप्रोसेसर कोटेड स्ट्रिंग्स को समझता है और उन्हें सामान्य टेक्स्ट से अलग तरीके से हैंडल करता है। स्ट्रिंग कॉन्फैनेटेशन इस विशेष उपचार का एक उदाहरण है। संदेश प्रागमा के लिए एक तर्क की आवश्यकता होती है जो एक उद्धृत स्ट्रिंग है। जब तर्क के लिए एक से अधिक घटक होते हैं तो वे सभी तार होने चाहिए ताकि स्ट्रिंग संघनन लागू हो सके। प्रीप्रोसेसर कभी भी यह नहीं मान सकता है कि एक अछूता स्ट्रिंग का इलाज किया जाना चाहिए जैसे कि इसे उद्धृत किया गया था। यदि यह तब किया:

#define ABC 123
int n = ABC;

संकलन नहीं होगा।

अब विचार करें:

#define ABC abc
#pragma message "The value of ABC is: " ABC

जो के बराबर है

#pragma message "The value of ABC is: " abc

यह एक प्रीप्रोसेसर चेतावनी का कारण बनता है क्योंकि एबीसी (अनक्विओटेड) को पूर्ववर्ती स्ट्रिंग के साथ समाहित नहीं किया जा सकता है।

अब प्रीप्रोसेसर स्ट्राइज़ पर विचार करें (जिसे कभी स्ट्रिंग कहा जाता था, संशोधित शब्दावली में प्रतिबिंबित करने के लिए दस्तावेज़ीकरण में लिंक बदल दिए गए हैं। आपके लिंक।)) ऑपरेटर। यह केवल एक मैक्रो के तर्कों पर कार्य करता है और अनपेक्षित तर्क को दोहरे उद्धरण चिह्नों में संलग्न तर्क से बदल देता है। इस प्रकार:

#define STR(x) #x
char *s1 = "abc";
char *s2 = STR(abc);

s1 और s2 के समान मान निर्दिष्ट करेगा। यदि आप gcc -E चलाते हैं, तो आप इसे आउटपुट में देख सकते हैं। शायद STR को ENQUOTE जैसा कुछ नाम दिया जाएगा।

यह एक अयोग्य वस्तु के चारों ओर उद्धरण लगाने की समस्या को हल करता है, अब समस्या यह है कि, यदि तर्क एक मैक्रो है, तो मैक्रो का विस्तार नहीं किया जाएगा। यही कारण है कि दूसरे मैक्रो की जरूरत है। XSTR ने अपने तर्क का विस्तार किया, फिर विस्तारित मान को उद्धरण में रखने के लिए STR को कॉल करता है।


3
मैं इसके लिए उत्सुक हूं कि इसके लिए दो चरणों की आवश्यकता क्यों है
विन्सेन्ट फोरमंड

4
@VincentFourmond XSTR चरण के बिना, मैक्रो का विस्तार नहीं किया गया है। इसलिए अगर आपने #define ABC 42 \ n STR (ABC) किया तो आपको "ABC" मिलेगा। Gcc.gnu.org/onbuildocs/cpp/Stringification.html
rob05c

यह Xcode 8 के साथ भी बढ़िया काम करता है, उदाहरण के लिए ABC की जगह __IPHONE_9_3
फफूंद

GCC शब्दावली बदल गई है, और इसके साथ URL, जो अब https://gcc.gnu.org/onbuildocs/cpp/Stringizing.html#Stringizing है
क्रिस बैरी

119

BOOST_PP_STRINGIZE सी ++ के लिए एक उत्कृष्ट समाधान लगता है, लेकिन नियमित सी के लिए नहीं।

यहाँ GNU CPP के लिए मेरा समाधान है:

/* Some test definition here */
#define DEFINED_BUT_NO_VALUE
#define DEFINED_INT 3
#define DEFINED_STR "ABC"

/* definition to expand macro then apply to pragma message */
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "="  VALUE(var)

/* Some example here */
#pragma message(VAR_NAME_VALUE(NOT_DEFINED))
#pragma message(VAR_NAME_VALUE(DEFINED_BUT_NO_VALUE))
#pragma message(VAR_NAME_VALUE(DEFINED_INT))
#pragma message(VAR_NAME_VALUE(DEFINED_STR))

उपरोक्त परिभाषाओं के परिणाम:

test.c:10:9: note: #pragma message: NOT_DEFINED=NOT_DEFINED
test.c:11:9: note: #pragma message: DEFINED_BUT_NO_VALUE=
test.c:12:9: note: #pragma message: DEFINED_INT=3
test.c:13:9: note: #pragma message: DEFINED_STR="ABC"

के लिए "interger के रूप में परिभाषित" , "स्ट्रिंग के रूप में परिभाषित" , और "परिभाषित लेकिन कोई मूल्य" चर, वे तो बस ठीक काम करते हैं। केवल "परिभाषित नहीं" चर के लिए, उन्होंने मूल चर नाम के समान ही प्रदर्शित किया। आपको इसका उपयोग करना होगा - या शायद कोई बेहतर समाधान प्रदान कर सकता है।


अति उत्कृष्ट! एआरएम आरवीसीटी में कोई अनुभव? ऐसा लगता है कि जीसीसी infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/- के
xdan

2
महान समाधान। हालाँकि, यदि मैं एक संकलित समय-गणना की गई मान के आकार को प्रदर्शित करना चाहता हूं, जैसे कि एक जटिल संरचना का आकार, क्या यह किया जा सकता है? इस उत्तर में सुझाई गई विधि उत्पन्न होती है DEFINED_INT=(sizeof(MY_STRUCT)), बिना sizeofऑपरेटर का मूल्यांकन किए।
कार्ल

(टिप्पणी जोड़: अप्रत्याशित नहीं है, क्योंकि यह प्री-प्रोसेसर के बजाय संकलक है जो मूल्यांकन करेगा sizeof, हालांकि, अभी भी उत्सुक है अगर इसे प्राप्त करने का एक चतुर तरीका है।)
कार्ल

@xdan अच्छा समाधान, दुर्भाग्य से चीजों के लिए पूरा नहीं किया जाता है#define masks {0xff, 0xaf, 0x0f}
साइमन Bagley

59

यदि आप दृश्य C ++ का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं #pragma message:

#include <boost/preprocessor/stringize.hpp>
#pragma message("BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION))

संपादित करें: लिंक के लिए LB का धन्यवाद

जाहिरा तौर पर, जीसीसी बराबर है (परीक्षण नहीं किया गया है):

#pragma message "BOOST_VERSION=" BOOST_PP_STRINGIZE(BOOST_VERSION)

5
इसे डायग्नोस्टिक प्रैग्मस कहा जाता है, gcc.gnu.org/oniltocs/gcc/…
LB40

4
अच्छा होगा यदि आप इसमें शामिल हैं जिसकी परिभाषाBOOST_PP_STRINGIZE अच्छी और छोटी है और कॉपी / पेस्ट करने योग्य है।
टिमम्म

जीसीसी के तहत ठीक काम करता है :)
थॉमस लेग्रिस

14

जहाँ तक मुझे पता है '#error' केवल स्ट्रिंग्स प्रिंट करेगा, वास्तव में आपको उद्धरण का उपयोग करने की आवश्यकता नहीं है

क्या आपने "BOOST_VERSION" का उपयोग करके विभिन्न उद्देश्यपूर्ण गलत कोड लिखने की कोशिश की है? शायद "ब्ला [BOOST_VERSION] = फू;" आपको कुछ बताएंगे जैसे "स्ट्रिंग शाब्दिक 1.2.1 का उपयोग एक सरणी पते के रूप में नहीं किया जा सकता है"। यह एक बहुत त्रुटि संदेश नहीं होगा, लेकिन कम से कम यह आपको प्रासंगिक मूल्य दिखाएगा। आप तब तक खेल सकते हैं जब तक आपको एक संकलन त्रुटि नहीं मिलती है जो आपको मूल्य बताता है।


यह काम नहीं किया, क्योंकि BOOST_VERSION एक पूर्णांक है, लेकिन मुझे यह इस कथन के साथ देखने को मिला: std::vector<BOOST_VERSION>;gcc 4.4.1 में। धन्यवाद!
जिम हंज़िकर

ध्यान दें कि दृश्य C ++ के साथ, आपको Bojan Resnik के उत्तर का उपयोग करना होगा।
राफेल सेंट-पियरे

मैंने इसे काम करने की कोशिश की, लेकिन जीसीसी ने मुझे जो त्रुटि संदेश दिया, वह दुखद रूप से अवांछनीय था। लेकिन इसका उल्लेख करने के लिए +1।
क्रिस लुत्ज़

14

बिना बढ़ावा:

  1. उसी मैक्रो को फिर से परिभाषित करें और कंपाइलर HIMSELF चेतावनी देगा।

  2. चेतावनी से आप पिछली परिभाषा का स्थान देख सकते हैं।

  3. vi पिछली परिभाषा की फाइल।

ambarish@axiom:~/cpp$ g++ shiftOper.cpp
shiftOper.cpp:7:1: warning: "LINUX_VERSION_CODE" redefined
shiftOper.cpp:6:1: warning: this is the location of the previous definition

#define LINUX_VERSION_CODE 265216
#define LINUX_VERSION_CODE 666

int main ()
{

}

यह आसान और सीधा है।
Tmx

1
खुद : संकलक का कोई लिंग नहीं है
स्काई

यह पूर्वनिर्धारित मैक्रो के साथ काम नहीं करता है, जैसे कि __cplusplus
मैनुएलटॉर्क

10

Microsoft C / C ++ में, आप अंतर्निहित _CRT_STRINGIZE()प्रिंट करने के लिए उपयोग कर सकते हैं । मेरी कई stdafx.hफाइलों में इनमें से कुछ संयोजन हैं:

#pragma message("_MSC_VER      is " _CRT_STRINGIZE(_MSC_VER))
#pragma message("_MFC_VER      is " _CRT_STRINGIZE(_MFC_VER))
#pragma message("_ATL_VER      is " _CRT_STRINGIZE(_ATL_VER))
#pragma message("WINVER        is " _CRT_STRINGIZE(WINVER))
#pragma message("_WIN32_WINNT  is " _CRT_STRINGIZE(_WIN32_WINNT))
#pragma message("_WIN32_IE     is " _CRT_STRINGIZE(_WIN32_IE))
#pragma message("NTDDI_VERSION is " _CRT_STRINGIZE(NTDDI_VERSION)) 

और इस तरह से कुछ आउटपुट:

_MSC_VER      is 1915
_MFC_VER      is 0x0E00
_ATL_VER      is 0x0E00
WINVER        is 0x0600
_WIN32_WINNT  is 0x0600
_WIN32_IE     is 0x0700
NTDDI_VERSION is 0x06000000

5
#define a <::BOOST_VERSION>
#include a
MSVC2015 : घातक त्रुटि C1083: खुले में फ़ाइल शामिल नहीं हो सकती: ':: 106200': ऐसी कोई फ़ाइल या निर्देशिका नहीं

preprocess to fileसक्षम होने पर भी काम करता है, भले ही अमान्य टोकन मौजूद हों:

#define a <::'*/`#>
#include a
MSVC2015 : घातक त्रुटि C1083: फ़ाइल को शामिल नहीं किया जा सकता है: ':: * * / `#': ऐसी कोई फ़ाइल या निर्देशिका
GCC4.x : चेतावनी: अनुपलब्ध समाप्ति का वर्ण [-Winvalid-pp-token,
#define a :: :: '* / `#>

मेरा बस कहता है Build error: #include expects "FILENAME" or <FILENAME>। आह।
एंडोलिथ

@endolith क्या संकलक और संस्करण?
एंड्री

DP8051 Keil 9.51 :)
एंडोलिथ

@endolith लगता है कि यह संकलक प्रीप्रोसेसिंग पर बहुत सीमित है: keil.com/support/man/docs/c51/c51_pp_directives.htm लेकिन, खदान की तरफ यह लगभग अपेक्षित रूप से काम करता है, मैंने अभी कुछ अमान्य वर्णों को हटाया है जैसे ':*** WARNING C318 IN LINE 2 OF test.c: can't open file '::*/`'
Andry

धन्यवाद, इसने मुझे बचाया क्योंकि मैं जिस कंपाइलर का उपयोग कर रहा था उसमें प्रज्ञा संदेश सामग्री लागू नहीं हुई थी।
कोडमोंकी

3

आप स्रोत फ़ाइल को प्रीप्रोसेस भी कर सकते हैं और देख सकते हैं कि प्रीप्रोसेसर वैल्यू का मूल्यांकन क्या है।


2

क्या आप देख रहे हैं

#if BOOST_VERSION != "1.2"
#error "Bad version"
#endif

बहुत अच्छा नहीं है अगर BOOST_VERSION एक स्ट्रिंग है, जैसे मैंने मान लिया है, लेकिन प्रमुख, लघु और संशोधन संख्याओं के लिए अलग-अलग पूर्णांकों को भी परिभाषित किया जा सकता है।


मुझे लगता है कि प्रस्तुतकर्ता किसी विशेष मूल्य को लागू नहीं करना चाहता है, वे यह देखना चाहते हैं कि वर्तमान मूल्य क्या है।
KeyserSoze

यही एक चीज है जो मेरे लिए काम करती है। मैं #if VARIABLE == 123मक्खी पर बयान बदल सकता हूं और वाक्य रचना हाइलाइटिंग मुझे बताता है कि क्या यह है कि मुझे लगता है कि यह है या नहीं ...
21

2

प्रीप्रोसेसर के आउटपुट को देखना आपके द्वारा पूछे गए उत्तर के लिए निकटतम चीज़ है।

मुझे पता है कि आपने उसे (और अन्य तरीकों से) बाहर कर दिया है, लेकिन मुझे यकीन नहीं है कि क्यों। आपके पास हल करने के लिए एक विशिष्ट पर्याप्त समस्या है, लेकिन आपने यह नहीं बताया है कि "सामान्य" विधियों में से कोई भी आपके लिए अच्छा काम क्यों नहीं करता है।


यह शायद सामान्य समस्या का सही उत्तर है।
jww

1

आप एक प्रोग्राम लिख सकते हैं जो प्रिंट करता है BOOST_VERSIONऔर आपके निर्माण प्रणाली के भाग के रूप में संकलित करता है और इसे चलाता है। अन्यथा, मुझे लगता है कि आप भाग्य से बाहर हैं।


हेडर में परिभाषित सॉफ़्टवेयर संस्करण के मामले में आप शायद सुरक्षित हैं (और यह एक अच्छा जवाब है)। लेकिन एक सामान्य समाधान के रूप में, एक संभावित नकारात्मक पहलू आपके परीक्षण ऐप और आपके वास्तविक ऐप को #define के समान मान प्राप्त करने में होगा - उनके शामिल रास्तों के आधार पर, अन्य #defines जिनका उपयोग उस एक के मान को सेट करने के लिए किया जा सकता है , CFLAGS संकलक को पास किया गया, आदि
KeyserSoze

अपने वास्तविक कार्यक्रम से इसे प्रिंट करें। यदि चित्रमय है, तो इसे "लगभग" संवाद में रखें। यदि कमांड-लाइन है, तो इसे एक विकल्प बनाएं (- वर्सन का हिस्सा, शायद)। यदि कोई डेमॉन है, तो उसे लॉग फ़ाइल में लिखें। यदि एम्बेडेड है, तो कोई अन्य तरीका खोजें।
divegeek

@swillden - ओपी इसे संकलन समय पर चाहता था, रनटाइम पर नहीं।
क्रिस लुत्ज

यह क्रॉस-कंपाइलर आधारित बिल्ड
क्रेग रिंगर


1

मैक्रो का उपयोग कैसे कर रहे हैं, इस बारे में बूस्ट प्रलेखन पर भी एक नज़र डालें:

के संदर्भ में BOOST_VERSION, से http://www.boost.org/doc/libs/1_37_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.boost_helper_macros :

XXYYZZ प्रारूप में बूस्ट संस्करण संख्या का वर्णन करता है जैसे: (BOOST_VERSION % 100)उप-लघु संस्करण है, लघु संस्करण है, और प्रमुख संस्करण है।((BOOST_VERSION / 100) % 1000)(BOOST_VERSION / 100000)


0

# फेर के बजाय, मैक्रो को पुनर्परिभाषित करने की कोशिश करें, इसके इस्तेमाल से पहले। संकलन विफल हो जाएगा और संकलक वर्तमान मूल्य प्रदान करेगा जो यह सोचता है कि मैक्रो पर लागू होता है।

#define BOOST_VERSION ब्लाह

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.