C / C ++ लाइन नंबर


110

डिबगिंग उद्देश्यों के लिए, क्या मुझे C / C ++ कंपाइलर में लाइन नंबर मिल सकता है ? (कुछ कंपाइलरों के लिए मानक तरीका या विशिष्ट तरीके)

जैसे

if(!Logical)
    printf("Not logical value at line number %d \n",LineNumber);
    // How to get LineNumber without writing it by my hand?(dynamic compilation)

17
@ लुकास: हम में से कुछ डिबगर्स के साथ गड़बड़ नहीं करना पसंद करते हैं। इस तरह के "गरीब व्यक्ति के मुखर बयान" कभी-कभी अधिक स्पष्ट होते हैं क्योंकि यह कोड का एक स्थायी हिस्सा है, और उन चीजों के स्थायी दस्तावेज़ीकरण है जो गणना की स्थिति के बारे में सही होना चाहिए।
S.Lott

13
@ लुकास: डिबगर लंबे समय से चलने वाले कार्यक्रमों में रुक-रुक कर आने वाली समस्याओं के लिए या क्लाइंट साइटों पर तैनात सॉफ्टवेयर में समस्याओं के बारे में जानकारी एकत्र करने के लिए भी उपयोगी नहीं हैं। इन मामलों में, कार्यक्रम का एकमात्र विकल्प कार्यक्रम की स्थिति के बारे में अधिक से अधिक जानकारी के लिए लॉग इन करना है, बाद के विश्लेषण के लिए।
कीथबी

1
@ लुकास और डिबगर इस जानकारी को प्राप्त करने के लिए कुछ एम्बेडेड सिस्टम पर इतनी अच्छी तरह से काम नहीं करते हैं।
जॉर्ज स्टॉकर

जवाबों:


180

आपको प्रीप्रोसेसर मैक्रो __LINE__और का उपयोग करना चाहिए __FILE__। वे पूर्वनिर्धारित मैक्रोज़ और सी / सी ++ मानक का हिस्सा हैं। प्रीप्रोसेसिंग के दौरान, उन्हें एक निरंतर स्ट्रिंग द्वारा वर्तमान लाइन संख्या का प्रतिनिधित्व करते हुए पूर्णांक धारण करके और वर्तमान फ़ाइल नाम द्वारा प्रतिस्थापित किया जाता है।

अन्य प्रीप्रोसेसर चर:

  • __func__: फ़ंक्शन नाम (यह C99 का हिस्सा है , सभी C ++ कंपाइलर इसका समर्थन नहीं करते हैं)
  • __DATE__ : फॉर्म की एक स्ट्रिंग "मम्म dd yyyy"
  • __TIME__ : "hh: mm: ss" फ़ॉर्म की एक स्ट्रिंग

आपका कोड होगा:

if(!Logical)
  printf("Not logical value at line number %d in file %s\n", __LINE__, __FILE__);

2
C99 __FunCTION__ के बजाय __func__ का उपयोग करता है, जो AFAIK आंशिक रूप से पदावनत है। अंतर आपके कोड को तोड़ सकता है, क्योंकि __func__ का उपयोग C के निरंतर स्ट्रिंग संघनन के लिए नहीं किया जा सकता है।
जोसेफ क्विन्से

1
जीसीसी मैनुअल से संदर्भ: "__FUNCTION__ और __PRETTY_FUNCTION__ को स्ट्रिंग शाब्दिक के रूप में माना जाता था; उन्हें चार सरणियों को इनिशियलाइज़ करने के लिए इस्तेमाल किया जा सकता था, और उन्हें अन्य स्ट्रिंग साहित्यिकों के साथ समाहित किया जा सकता था। जीसीसी 3.4 और बाद में उन्हें __func__, जैसे C ++, __FUNCTION__ के रूप में चर के रूप में माना जाता है। और __PRETTY_FUNCTION__ हमेशा चर रहे हैं। "
जोसेफ क्विंसे

क्या लाइन नंबर को स्ट्रिंग के रूप में प्राप्त करने का एक तरीका है, फ़ाइल नाम के समान? मैं चाहूंगा कि प्रीप्रोसेसर मुझे दे दे जैसे कि स्ट्रिंग शाब्दिक "22" पूर्णांक 22 के बजाय।
sep332

1
@ sep332 हाँ, लेकिन सीपीपी एक अजीब जानवर है, इसलिए इसे मैक्रो तर्कों के साथ दो चरणों में किया जाना चाहिए। #define S1(N) #N #define S2(N) S1(N) #define LINESTR S2(__LINE__)। देखें c-faq.com/ansi/stringize.html
काज

1
सख्ती से कहना, __func__एक मैक्रो नहीं है, यह एक अंतर्निहित घोषित चर है।
३C को होलीब्लैककैट

64

C ++ मानक के हिस्से के रूप में कुछ पूर्व-निर्धारित मैक्रोज़ मौजूद हैं जिनका आप उपयोग कर सकते हैं। C ++ मानक की धारा 16.8 अन्य चीजों के बीच, __LINE__मैक्रो को परिभाषित करती है ।

__LINE__: वर्तमान स्रोत लाइन की लाइन संख्या (एक दशमलव स्थिर)।
__FILE__: स्रोत फ़ाइल (एक चरित्र स्ट्रिंग शाब्दिक) का अनुमानित नाम।
__DATE__: स्रोत फ़ाइल के अनुवाद की तारीख (एक चरित्र स्ट्रिंग शाब्दिक ...)
__TIME__: स्रोत फ़ाइल के अनुवाद का समय (एक चरित्र स्ट्रिंग शाब्दिक ...)
__STDC__: क्या __STDC__पूर्वनिर्धारित है
__cplusplus: नाम __cplusplusको मूल्य 199711L में परिभाषित किया गया है C ++ अनुवाद इकाई का संकलन

तो आपका कोड होगा:

if(!Logical)
  printf("Not logical value at line number %d \n",__LINE__);

19

आप प्रिंटफ़ () के समान व्यवहार वाले मैक्रो का उपयोग कर सकते हैं , सिवाय इसके कि इसमें डिबग जानकारी जैसे फ़ंक्शन का नाम, वर्ग और लाइन नंबर भी शामिल है:

#include <cstdio>  //needed for printf
#define print(a, args...) printf("%s(%s:%d) " a,  __func__,__FILE__, __LINE__, ##args)
#define println(a, args...) print(a "\n", ##args)

इन मैक्रोज़ को प्रिंटफ () के लिए व्यावहारिक रूप से व्यवहार करना चाहिए , जबकि जावा स्टैच्रेस-जैसी जानकारी भी शामिल है। यहाँ एक उदाहरण मुख्य है:

void exampleMethod() {
    println("printf() syntax: string = %s, int = %d", "foobar", 42);
}

int main(int argc, char** argv) {
    print("Before exampleMethod()...\n");
    exampleMethod();
    println("Success!");
}

निम्नलिखित आउटपुट में कौन सा परिणाम है:

main (main.cpp: 11) exampleMethod () से पहले ...
exampleMethod (main.cpp: 7) printf () सिंटैक्स: string = foobar, int = 42
main (main.cpp: 13) सफलता!


c विकास के लिए, आप #include<stdio.h>
phyatt

11

उपयोग __LINE__(यह डबल-अंडरस्कोर लाइन डबल-अंडरस्कोर है), प्रीप्रोसेसर इसे उस लाइन नंबर के साथ बदल देगा जिस पर यह सामना किया गया है।



5

C ++ 20 std :: source_location का उपयोग करके इसे प्राप्त करने का एक नया तरीका प्रदान करता है । यह वर्तमान में gcc के std::experimental::source_locationसाथ क्लच के रूप में उपलब्ध है #include <experimental/source_location>

मैक्रोज़ जैसी समस्या यह __LINE__है कि यदि आप उदाहरण के लिए एक लॉगिंग फ़ंक्शन बनाना चाहते हैं जो एक संदेश के साथ-साथ वर्तमान लाइन नंबर को आउटपुट करता है, तो आपको हमेशा __LINE__फ़ंक्शन तर्क के रूप में पास करना होगा , क्योंकि यह कॉल साइट पर विस्तारित है। कुछ इस तरह:

void log(const std::string msg) {
    std::cout << __LINE__ << " " << msg << std::endl;
}

हमेशा फ़ंक्शन डिक्लेरेशन की लाइन को आउटपुट करेगा और उस लाइन को नहीं जहां logसे वास्तव में बुलाया गया था। दूसरी ओर, std::source_locationआप कुछ इस तरह से लिख सकते हैं:

#include <experimental/source_location>
using std::experimental::source_location;

void log(const std::string msg, const source_location loc = source_location::current())
{
    std::cout << loc.line() << " " << msg << std::endl;
}

यहां, locउस स्थान को इंगित करते हुए लाइन नंबर के साथ आरंभ logकिया जाता है जहां पर कॉल किया गया था। आप इसे यहाँ ऑनलाइन आज़मा सकते हैं।


4

कोशिश करो __FILE__और __LINE__
तुम भी मिल सकता है __DATE__और __TIME__उपयोगी हो सकता है।
हालाँकि जब तक आपको क्लाइंटसाइड पर किसी प्रोग्राम को डिबग नहीं करना पड़ता है और इस तरह से इन informations को लॉग इन करने की आवश्यकता होती है, आपको सामान्य डिबगिंग का उपयोग करना चाहिए।


मुझे इस पर क्यों वोट दिया गया और क्यों खरीदारों ने मेरे पोस्ट को संपादित किया?
Sanctus2099

@ Sanctus2099: इसे संपादित किया गया था, क्योंकि मार्कडेल ने FILE और LINE को बोल्ड फॉन्ट में प्रदर्शित करने के लिए आपके डबल अंडरस्कोर को बदल दिया (क्या आप यह नहीं जांचते हैं कि आपका उत्तर कैसा दिखता है?)। एक और बिंदु यह हो सकता है (कम से कम यह अब मुझे इस तरह दिखता है) कि आपने पहले ही सही उत्तर दिए जाने के 1 घंटे बाद उत्तर दिया था, इसलिए आपने कोई मूल्य नहीं जोड़ा।
फेलिक्स क्लिंग

डबल अंडरस्कोर बोल्ड के लिए मार्कअप सिंटैक्स है । डबल अंडरस्कोर को ठीक से प्रदर्शित करने के लिए, आपको उन्हें (इस तरह: \ _ \ _) से बचना होगा या उन्हें raw codeइस तरह (जैसे: `__`) चिह्नित करने के लिए बैकटिक्स का उपयोग करना होगा। @ खरीदारों ने मदद करने का प्रयास किया, लेकिन वह केवल एक अंडरस्कोर से बच गया, और इस तरह आप इटैलिक के लिए मार्कअप सिंटैक्स के साथ छोड़ दिया गया । डाउनवोट्स यहां थोड़ा कठोर हैं, हालांकि, मैं सहमत हूं।
मैट बी

ठीक है मुझे इस बात का अंदाजा नहीं था कि डबल अंडरस्कोर की वजह से टेक्स्ट बोल्ड हो जाता है और मुझे जाना पड़ता है और मेरे पास यह देखने का समय नहीं होता कि मेरा जवाब कैसा लग रहा है। मुझे अब समझ में आया। भले ही मेरा जवाब एक घंटा देर से था फिर भी यह एक अच्छा जवाब था। इसमें कोई मूल्य नहीं जोड़ा गया, लेकिन यह गलत नहीं था, इसलिए कोई भी कारण नहीं था। मदद के लिए कोशिश करने पर आपको यही मिलेगा ...
Sanctus2099

2
@ Sanctus2099 कुछ लोगों को वोट डालने की जल्दी है, इसीलिए यह सुनिश्चित करना महत्वपूर्ण है कि आपका उत्तर सही हो। इस मामले में, आपने एक गलत उत्तर पोस्ट किया और इसे 4 घंटे के लिए छोड़ दिया। आपको कोई नहीं बल्कि खुद को दोषी मानना ​​है।
meagar

1

चूंकि मैं भी अब इस समस्या का सामना कर रहा हूं और मैं यहां पूछे गए एक अलग लेकिन मान्य प्रश्न का उत्तर नहीं जोड़ सकता , इसलिए मैं इस समस्या के लिए एक उदाहरण समाधान प्रदान करूंगा: केवल उस पंक्ति की संख्या प्राप्त करना जहां फ़ंक्शन को बुलाया गया है C ++ टेम्प्लेट का उपयोग करते हुए।

पृष्ठभूमि: C ++ में एक टेम्पलेट तर्क के रूप में गैर-प्रकार पूर्णांक मानों का उपयोग कर सकते हैं। यह टेम्पलेट तर्कों के रूप में डेटा प्रकारों के विशिष्ट उपयोग से अलग है। तो विचार यह है कि फ़ंक्शन कॉल के लिए ऐसे पूर्णांक मानों का उपयोग करें।

#include <iostream>

class Test{
    public:
        template<unsigned int L>
        int test(){
            std::cout << "the function has been called at line number: " << L << std::endl;
            return 0;
        }
        int test(){ return this->test<0>(); }
};

int main(int argc, char **argv){
    Test t;
    t.test();
    t.test<__LINE__>();
    return 0;
}

आउटपुट:

फ़ंक्शन को लाइन नंबर: 0 पर बुलाया गया है

फ़ंक्शन को लाइन नंबर: 16 पर बुलाया गया है

यहाँ उल्लेख करने के लिए एक बात यह है कि C ++ 11 मानक में टेम्पलेट का उपयोग करके फ़ंक्शन के लिए डिफ़ॉल्ट टेम्पलेट मान देना संभव है। गैर-प्रकार के तर्कों के लिए पूर्व C ++ 11 डिफ़ॉल्ट मान केवल क्लास टेम्पलेट तर्कों के लिए काम करते हैं। इस प्रकार, C ++ 11 में, ऊपर की तरह डुप्लिकेट फ़ंक्शन परिभाषाओं को रखने की कोई आवश्यकता नहीं होगी। सी ++ 11 में इसकी भी स्थिरांक चार * टेम्पलेट तर्क लेकिन उनकी तरह शाब्दिक साथ उपयोग करने के लिए संभव नहीं है के लिए वैध __FILE__या __func__उल्लेख किया यहाँ

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


1

उपयोग करें __LINE__, लेकिन इसका प्रकार क्या है?

लाइन वर्तमान स्रोत लाइन (एक पूर्णांक स्थिरांक) के प्रकल्पित लाइन नंबर (वर्तमान स्रोत फ़ाइल के भीतर)।

एक के रूप में पूर्णांक निरंतर , कोड अक्सर यह मान सकते हैं मूल्य है __LINE__ <= INT_MAXऔर इतने प्रकार है int

सी में मुद्रित करने के लिए, printf()मिलान निर्दिष्ट करने की आवश्यकता है "%d":। C ++ में यह बहुत कम चिंता का विषय है cout

पेडिक चिंता: यदि पंक्ति संख्या INT_MAX1 (16-बिट के साथ कुछ बोधगम्य int) से अधिक है, तो उम्मीद है कि संकलक एक चेतावनी का उत्पादन करेगा। उदाहरण:

format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]

वैकल्पिक रूप से, कोड इस तरह की चेतावनियों को व्यापक प्रकार के लिए मजबूर कर सकता है।

printf("Not logical value at line number %ld\n", (long) __LINE__);
//or
#include <stdint.h>
printf("Not logical value at line number %jd\n", INTMAX_C(__LINE__));

बचें printf()

सभी पूर्णांक सीमाओं से बचने के लिए: स्ट्रिंग करें । कोड printf()कॉल के बिना सीधे प्रिंट कर सकता है : त्रुटि से बचने के लिए एक अच्छी बात 2

#define xstr(a) str(a)
#define str(a) #a

fprintf(stderr, "Not logical value at line number %s\n", xstr(__LINE__));
fputs("Not logical value at line number " xstr(__LINE__) "\n", stderr);

1 निश्चित रूप से खराब प्रोग्रामिंग प्रैक्टिस के लिए इतनी बड़ी फ़ाइल होती है, फिर भी शायद मशीन जनित कोड अधिक हो सकता है।

2 डिबगिंग में, कभी-कभी कोड बस आशा के अनुसार काम नहीं कर रहा है। जैसे जटिल कार्यों को कॉल *printf()करना मुद्दों को बनाम एक सरल तरीके से उकसा सकता है fputs()


1

उन लोगों के लिए जिन्हें इसकी आवश्यकता हो सकती है, एक "FILE_LINE" मैक्रो आसानी से फ़ाइल और लाइन प्रिंट करने के लिए:

#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.