Ubuntu 12.04 पर GCC के साथ संकलन नहीं कर सकते


9

मैं अपने Ubuntu और Windows मशीनों पर GCC और VC9 दोनों के साथ नीचे C प्रोग्राम को संकलित करने और चलाने का प्रयास कर रहा हूं। हालाँकि, मैं नीचे दिए गए मुद्दों का सामना कर रहा हूँ:

उबंटू मशीन पर:

जीसीसी ठीक संकलित करता है, लेकिन जब चलाया जाता है, तो मुझे यह संकेत दिया जाता है:

Segmentation Fault (Core Dump).

विंडोज मशीन पर:

VC9 संकलन और ठीक चलता है। जीसीसी ठीक संकलित करता है, लेकिन कार्यक्रम समाप्त होने पर प्रक्रिया समाप्त हो जाती है।

यहां अपने विशेषज्ञ की सहायता की आवश्यकता है। यहाँ मेरा कोड है:

#include <string.h>
#include <stdio.h>

int calc_slope(int input1,int input2)
{
    int sum=0;
    int start=input1;
    int end=input2;
    int curr=start;

    //some validation:
    if (input1>input2)
        return -1;


    while(curr<=end)
    {
        if (curr>100)
        {
            char *s="";
            int length;
            int left;
            int right;
            int cent;

            sprintf(s,"%d",curr);
            length=strlen(s);
            s++;
            do
            {
                //printf("curr=%d char=%c pointer=%d length=%d \n",curr,*s,s,length);
                left = *(s-1) - '0';
                cent = *s - '0';
                right = *(s+1) - '0';
                //printf("curr=%d l=%d c=%d r=%d\n",curr,left,cent,right);
                if ( (cent>left && cent>right) || (cent<left && cent<right) )
                {
                    sum+=1; //we have either a maxima or a minima.
                }

                s++;
            } while (*(s+1)!='\0');
        }
        curr++;
    }

    return sum;
}

int main()
{
    printf("%d",calc_slope(1,150));
    return 0;
}

अपडेट करें:

न केवल त्रुटि को ट्रैक करने में मेरी मदद करने के लिए श्रेय एलियाह को जाता है , बल्कि यह मुझे gdbऔर इसके बैक-ट्रेसिंग टूल ( bt) से भी परिचित कराता है, जो एक जीसीसी संकलित कार्यक्रम को डीबग करने में सहायक होते हैं। यहाँ संशोधित संस्करण है, मैंने कुछ परीक्षण और त्रुटि के बाद काम किया:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int calc_slope(int input1,int input2)
{
    int sum=0;
    int start=input1;
    int end=input2;
    int curr=start;

    //some validation:
    if (input1>input2)
        return -1;


    while(curr<=end)
    {
        if (curr>100)
        {
            int size=10;
            char *s=(char*)malloc((size+1) * sizeof(char));
            int left;
            int right;
            int cent;

            sprintf(s,"%d",curr);
            s++;
            do
            {
                left = *(s-1) - '0';
                cent = *s - '0';
                right = *(s+1) - '0';
                if ( (cent>left && cent>right) || (cent<left && cent<right) )
                {
                    sum+=1; //we have either a maxima or a minima.
                }

                s++;
            } while (*(s+1)!='\0');
        }
        curr++;
    }

    return sum;
}

int main()
{
    printf("%d",calc_slope(1,150));
    return 0;
}

3
मुझे लगता है कि यह एक संकलन मुद्दा नहीं है, बल्कि एक रनटाइम मुद्दा है। आपको StackOverflow से अधिक मदद मिलेगी ।
ओस्कामे

क्या आपको यकीन है कि VC9 के साथ संकलित होने के बाद यह वास्तव में ठीक चलता है?
एलियाह कगन

हां, 100%। लेकिन जीसीसी के साथ नहीं।
प्रहलाद यारी

@ प्रह्लादप्रिय शीतल! मैंने अपने उत्तर में इसके कारण बताए हैं । (इसका मतलब यह भी है कि हमें शायद इस सवाल पर विचार करना चाहिए, क्योंकि यह Ubuntu * -स्पेशल * व्यवहार के बारे में है। विंडोज में जीसीसी तुलनीय व्यवहार प्रदर्शित करता है, लेकिन कोई त्रुटि संदेश नहीं है और यह जानना मुश्किल है कि वास्तव में वहां क्या हो रहा है - इसके अलावा, जब उबंटू और माइक्रोसॉफ्ट विजुअल C ++ पर जीसीसी अलग तरीके से काम करते हैं, मुझे लगता है कि उबंटू पूछना एक उचित जगह है कि उबंटू पर जीसीसी क्यों काम करता है क्योंकि यह कहा गया है। आगे कहा गया है कि यह सही स्टैक ओवरफ्लो पर कैसे होता है ।)
एलिया कागन

सी में एक स्ट्रिंग शाब्दिक संशोधन अपरिभाषित व्यवहार है। कृपया याद रखें।
jn1kk 22

जवाबों:


15

एक विभाजन दोष तब होता है जब कोई प्रोग्राम उस क्षेत्र के बाहर मेमोरी तक पहुंचने की कोशिश करता है जिसे इसके लिए आवंटित किया गया है।

इस मामले में, एक अनुभवी सी प्रोग्रामर देख सकता है कि समस्या उस रेखा में हो रही है जहां sprintfकहा जाता है। लेकिन अगर आप यह नहीं बता सकते हैं कि आपका विभाजन दोष कहाँ हो रहा है, या यदि आप इसे जानने की कोशिश करने के लिए कोड के माध्यम से पढ़ने की जहमत नहीं उठाना चाहते हैं , तो आप अपने प्रोग्राम को डिबग प्रतीकों (साथ gcc, -gध्वज ) के साथ बना सकते हैं ) और फिर इसे डिबगर के माध्यम से चलाएं।

मैंने आपके स्रोत कोड की प्रतिलिपि बनाई और इसे मेरे द्वारा नामित फ़ाइल में पेस्ट कर दिया slope.c। फिर मैंने इसे इस तरह बनाया:

gcc -Wall -g -o slope slope.c

( -Wallवैकल्पिक है। यह सिर्फ अधिक स्थितियों के लिए चेतावनी का उत्पादन करने के लिए है। यह पता लगाने में मदद कर सकता है कि क्या गलत हो सकता है, भी।)

तब मैंने प्रोग्राम शुरू करने के लिए gdbपहले डिबगर में प्रोग्राम चलाया, और फिर डिबगर में एक बार, डिबगर को कमांड दे रहा था :gdb ./slopegdbrun

ek@Kip:~/source$ gdb ./slope
GNU gdb (GDB) 7.5-ubuntu
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/ek/source/slope...done.
(gdb) run
Starting program: /home/ek/source/slope 
warning: Cannot call inferior functions, you have broken Linux kernel i386 NX (non-executable pages) support!

Program received signal SIGSEGV, Segmentation fault.
0x001a64cc in _IO_default_xsputn () from /lib/i386-linux-gnu/libc.so.6

(मेरे you have broken Linux kernel i386 NX... supportसंदेश के बारे में चिंता मत करो , यह gdbप्रभावी ढंग से इस कार्यक्रम को डीबग करने से रोका नहीं जा सकता है।)

यह जानकारी अत्यधिक गूढ़ है ... और यदि आपके पास libc के लिए डिबग प्रतीक स्थापित नहीं हैं, तो आपको एक और भी अधिक गूढ़ संदेश मिलेगा जिसमें प्रतीकात्मक फ़ंक्शन नाम के बजाय हेक्साडेसिमल पता होगा _IO_default_xsputn। सौभाग्य से, इससे कोई फर्क नहीं पड़ता, क्योंकि हम वास्तव में जानना चाहते हैं कि आपके कार्यक्रम में समस्या कहां है।

तो, समाधान पीछे की ओर देखना है, यह देखने के लिए कि सिस्टम लाइब्रेरी में उस विशेष फ़ंक्शन कॉल के लिए कौन-सी फ़ंक्शन कॉल हुईं, जहां SIGSEGVसिग्नल को अंततः ट्रिगर किया गया था।

gdb(और किसी भी डीबगर) में इस सुविधा का निर्माण किया गया है: इसे स्टैक ट्रेस या बैकट्रेस कहा जाता है । मैं btएक backtrace उत्पन्न करने के लिए डीबगर कमांड का उपयोग करता हूं gdb:

(gdb) bt
#0  0x001a64cc in _IO_default_xsputn () from /lib/i386-linux-gnu/libc.so.6
#1  0x00178e04 in vfprintf () from /lib/i386-linux-gnu/libc.so.6
#2  0x0019b234 in vsprintf () from /lib/i386-linux-gnu/libc.so.6
#3  0x0017ff7b in sprintf () from /lib/i386-linux-gnu/libc.so.6
#4  0x080484cc in calc_slope (input1=1, input2=150) at slope.c:26
#5  0x08048578 in main () at slope.c:52
(gdb)

आप देख सकते हैं कि आपका mainफ़ंक्शन फ़ंक्शन को कॉल करता calc_slopeहै (जो आपने इरादा किया है), और फिर calc_slopeकॉल करता है sprintf, जो (इस सिस्टम पर) कॉल के साथ कार्यान्वित किया गया है और कुछ अन्य संबंधित पुस्तकालय कार्यों के लिए।

आप आमतौर पर जिस चीज में रुचि रखते हैं, वह आपके प्रोग्राम में फ़ंक्शन कॉल है जो आपके प्रोग्राम के बाहर एक फ़ंक्शन को कॉल करती है । जब तक पुस्तकालय / पुस्तकालयों में कोई बग न हो जिसे आप उपयोग कर रहे हैं (इस मामले में, मानक सी लाइब्रेरी libcलाइब्रेरी फ़ाइल द्वारा प्रदान की जाती है libc.so.6), बग जो दुर्घटना का कारण बनता है वह आपके कार्यक्रम में है और अक्सर या उसके पास या उसके पास होगा आपके कार्यक्रम में अंतिम कॉल

इस मामले में, यह है:

#4  0x080484cc in calc_slope (input1=1, input2=150) at slope.c:26

यहीं से आपका कार्यक्रम पुकारता है sprintf। हम इसे जानते हैं क्योंकि sprintfअगला कदम है। लेकिन यहां तक ​​कि यह बताते हुए कि, आप यह जानते हैं क्योंकि यह वही है जो लाइन 26 पर होता है , और यह कहता है:

... at slope.c:26

आपके प्रोग्राम में, लाइन 26 में शामिल हैं:

            sprintf(s,"%d",curr);

(आपको हमेशा एक पाठ संपादक का उपयोग करना चाहिए जो स्वचालित रूप से लाइन नंबर दिखाता है, कम से कम उस पंक्ति के लिए जो आप वर्तमान में हैं। यह संकलन-समय त्रुटियों दोनों की व्याख्या करने में बहुत सहायक है, और डिबगर का उपयोग करते समय रनटाइम समस्याओं का पता चलता है।)

जैसा कि डेनिस कार्सेमाकर के जवाब में चर्चा की गई है , sएक-एक बाइट है। (शून्य नहीं है, क्योंकि आपने जो मान दिया है "", वह एक बाइट लंबी है, यानी यह { '\0' }उसी के बराबर है , उसी तरह है "Hello, world!\n"जो बराबर है { 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n', '\0' }।)

तो, क्यों यह अभी भी कुछ मंच पर काम कर सकता है (और जाहिर है जब विंडोज के लिए VC9 के साथ संकलित किया जाता है)?

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

दूसरे शब्दों में, कुछ भी हो सकता है!

फिर भी, कुछ चीजें दूसरों की तुलना में अधिक संभावना हैं। ऐसा क्यों है कि स्टैक पर एक छोटा सा सरणी, कुछ कार्यान्वयन पर, स्टैक पर एक बड़े सरणी की तरह काम करता दिखाई देता है?

यह नीचे आता है कि स्टैक आवंटन कैसे लागू किया जाता है, जिसे प्लेटफ़ॉर्म से प्लेटफ़ॉर्म पर अलग-अलग करने की अनुमति है। आपका निष्पादन योग्य अपने स्टैक की तुलना में अधिक मेमोरी आवंटित कर सकता है, जिसका वास्तव में किसी एक समय में उपयोग करने का इरादा है। कभी-कभी यह आपको स्मृति स्थानों पर लिखने की अनुमति दे सकता है जो आपने अपने कोड में स्पष्ट रूप से दावा नहीं किया है । यह बहुत संभव है कि जब VC9 में आपका प्रोग्राम बन जाए तो यही हो।

हालाँकि, आपको VC9 में भी इस व्यवहार पर भरोसा नहीं करना चाहिए। यह संभावित रूप से पुस्तकालयों के विभिन्न संस्करणों पर निर्भर हो सकता है जो विभिन्न विंडोज सिस्टम पर मौजूद हो सकते हैं। लेकिन इससे भी अधिक समस्या यह है कि अतिरिक्त स्टैक स्पेस को इस आशय के साथ आवंटित किया जाता है कि यह वास्तव में उपयोग किया जाएगा, और इसलिए इसका वास्तव में उपयोग किया जा सकता है।तब आप "अपरिभाषित व्यवहार" की पूरी रात का अनुभव करते हैं, जहां, इस मामले में, एक से अधिक चर एक ही स्थान पर संग्रहीत किए जा सकते हैं, जहां एक को लिखना दूसरे को अधिलेखित करता है ... लेकिन हमेशा नहीं, क्योंकि कभी-कभी चर को लिखता है रजिस्टरों में कैश किया जाता है और वास्तव में तुरंत नहीं किया जाता है (या चर को पढ़ता है, कैश किया जा सकता है, या एक वैरिएबल को उसी तरह माना जा सकता है जैसा कि पहले था, क्योंकि इसे आवंटित की गई मेमोरी को कंपाइलर के माध्यम से नहीं लिखा जाता है। चर)।

और यह मुझे इस बात के लिए अन्य संभावित संभावना के लिए लाता है कि जब वीसी 9 के साथ बनाया गया था तो कार्यक्रम क्यों काम किया। यह संभव है, और कुछ हद तक संभावना है कि एक सरणी बाइट के बाद स्थान का उपयोग करने के लिए कुछ सरणी या अन्य चर वास्तव में आपके प्रोग्राम द्वारा आवंटित किया गया था (जिसमें आपके प्रोग्राम का उपयोग कर रहे एक पुस्तकालय द्वारा आवंटित किया जा सकता है) s। तो, sएक बाइट की तुलना में लंबे समय तक एक सरणी के रूप में व्यवहार करने से उस / उन चर / सरणियों की सामग्री तक पहुंचने का प्रभाव होगा, जो खराब भी हो सकते हैं।

अंत में, जब आप इस तरह की गलती करते हैं, तो "सेगमेंटेशन फॉल्ट" या "सामान्य सुरक्षा दोष" जैसी त्रुटि प्राप्त करना भाग्यशाली होता है। जब आपके पास ऐसा नहीं होता है, तब तक आपको पता नहीं चल सकता है कि जब तक आपके कार्यक्रम का अपरिभाषित व्यवहार नहीं हो जाता है तब तक बहुत देर हो चुकी है


1
इस तरह की स्पष्ट व्याख्या के लिए धन्यवाद। यह वही है जो मुझे चाहिए था .. !!
प्रहलाद यारी

9

हैलो बफर अतिप्रवाह!

char *s="";
sprintf(s,"%d",curr);
length=strlen(s);

आप स्टैक पर एक स्ट्रिंग के लिए एक बाइट आवंटित करते हैं और फिर एक से अधिक बाइट लिखने के लिए आगे बढ़ते हैं। और इसे बंद करने के लिए, आप उस सरणी के अंत से परे पढ़ते हैं। कृपया सी मैनुअल और विशेष रूप से स्ट्रिंग्स पर अनुभाग पढ़ें और उनके लिए मेमोरी आवंटित करें।


हां मुझे उस बारे में बाद में पता चला। लेकिन जब मैंने यह लिखा, तो VC9 कंपाइलर ने न केवल अनुमति दी, बल्कि मुझे परिणाम भी ठीक से दिखाए। मैंने स्ट्रलेन-एड को प्रिंट-एड किया और इसने मुझे 4 दिखाया, न कि 1 !!
प्रहलाद यारी

क्या आप मुझे सलाह भी दे सकते हैं कि मुझे इसे कैसे ठीक करना चाहिए? जैसा कि आपने कोड से अधिभूत किया होगा, मेरे पास पहले से तय आकार को आवंटित करने का कोई तरीका नहीं है। इसकी लंबाई वक्र चर में अंकों की संख्या है जिसे तब तक नहीं जाना जा सकता जब तक कि मैं इसे स्ट्रिंग में नहीं बदल देता !! ?
प्रहलाद यारी

मैं कर सकता हूं, लेकिन आपको वास्तव में प्रोग्रामिंग सलाह के लिए स्टैक ओवरफ्लो को छोड़ देना चाहिए, क्योंकि यह यहां काफी ऑफटॉपिक है।
डेनिस करसेमेकर

1
@DennisKaarsemaker यहां मूल प्रश्न शायद ऑफ-टॉपिक नहीं हो सकता क्योंकि इसमें स्पष्ट रूप से व्यवहार शामिल है जो उबंटू और एक अन्य मंच के बीच भिन्न होता है (और मैंने अपने उत्तर में इसके लिए सबसे संभावित कारण समझाया है )। मैं इस बात से सहमत हूं कि सी में स्ट्रिंग्स को कैसे आवंटित किया जाए, इस बारे में सवाल स्टैक ओवरफ्लो पर हैं और यहां नहीं।
एलियाह कगन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.