سلوك printf عند طباعة٪ د دون تزويد اسم المتغير

StackOverflow https://stackoverflow.com/questions/437816

  •  22-07-2019
  •  | 
  •  

سؤال

ولقد واجهت مجرد مشكلة غريبة، وأنا أحاول أن printf متغير عدد صحيح، ولكن نسيت لتحديد اسم متغير، أي بمعنى.

printf("%d");

وبدلا من

printf("%d", integerName);

والمثير للدهشة برنامج يجمع، هناك انتاج وليس عشوائي. في الواقع، كان يحدث أن يكون صحيحا جدا أردت أن الطباعة في المقام الأول، والذي صادف أن يكون م-1.

والبيان printf errorneous سيتم إخراج باستمرار م-1 لطالما يحافظ على برنامج تشغيل ... وبعبارة أخرى، انها تتصرف تماما كما لو يقرأ بيان

printf("%d", m-1);

وأي شخص يعرف السبب وراء هذا السلوك؟ أنا باستخدام ز ++ دون أي خيارات سطر الأوامر.

#include <iostream>
#define maxN 100
#define ON 1
#define OFF 0

using namespace std;

void clearArray(int* array, int n);
int fillArray(int* array, int m, int n);

int main()
{
    int n = -1, i, m;
    int array[maxN];
    int found;

    scanf("%d", &n);

    while(n!=0)
    {
        found=0;
        m = 1;
        while(found!=1)
        {
            if(m != 2 && m != 3 && m != 4 && m != 6 && m != 12)
            {
                clearArray(array, n);
                if(fillArray(array, m, n) == 0)
                {
                    found = 1;
                }
            }
            m++;
        }

        printf("%d\n");

        scanf("%d", &n);
    }

    return 0;
}

void clearArray(int* array, int n)
{
    for(int i = 1; i <= n; i++)
        array[i] = ON;
}

int fillArray(int* array, int m, int n)
{
    int i = 1, j, offCounter = 0, incrementCounter;

    while(offCounter != n)
    {
        if(*(array+i)==ON) 
        {
            *(array+i) = OFF;
            offCounter++;       
        }
        else 
        {
            j = 0;
            while((*array+i+j)==OFF)
            {
                j++;
            }
            *(array+i+j) = OFF;
            offCounter++;           
        }
        if(*(array+13) == OFF && offCounter != n) return 1;
        if(offCounter ==n) break;

        incrementCounter = 0;       
        while(incrementCounter != m)
        {
            i++;
            if(i > n) i = 1;
            if(*(array+i) == ON) incrementCounter++; 
        }       
    }

    return 0;
}
هل كانت مفيدة؟

المحلول

وأنت تقول أن "الغريب ان برنامج يجمع". في الواقع، فإنه ليس من المستغرب على الإطلاق. C & C ++ تسمح للوظائف لديها قوائم حجة المتغيرة. تعريف printf شيء من هذا القبيل:

int printf(char*, ...);

وو"..." يدل على أن هناك الصفر أو أكثر اختيارية الحجج على وظيفة. في الواقع، واحدة من الأسباب الرئيسية C لديها الوسائط الاختيارية هو دعم الأسرة printf و scanf من الوظائف.

وC لا يوجد لديه معرفة خاصة وظيفة printf. في المثال الخاص بك:

printf("%d");

والمترجم لا تحليل سلسلة التنسيق وتحديد أن حجة صحيحا مفقود. هذا هو رمز C قانوني تماما. حقيقة أن كنت في عداد المفقودين حجة هي قضية الدلالات التي تظهر فقط في وقت التشغيل. فإن وظيفة printf نفترض أن لديك زودت حجة وتذهب تبحث عن ذلك على المكدس. وسوف تلتقط كل ما يحدث أن تكون هناك. انها مجرد يحدث ذلك في حالة خاصة بك هو طباعة الشيء الصحيح، ولكن هذا هو الاستثناء. بشكل عام سوف تحصل البيانات القمامة. سوف تختلف هذا السلوك من مترجم إلى المترجم، وسوف تتغير أيضا اعتمادا على ما يجمع الخيارات التي استخدامها؛ إذا قمت بالتبديل على تحسين مترجم هل من المحتمل أن تحصل على نتائج مختلفة.

وكما ورد في أحد التعليقات على جوابي، بعض المجمعين لها "الوبر" مثل القدرات التي يمكن الكشف عن الواقع المكالمات printf / scanf الخاطئة. وهذا ينطوي على مترجم تحليل سلسلة التنسيق وتحديد عدد من الحجج إضافية المتوقع. هذا هو السلوك مترجم خاص جدا ولن كشف عن الأخطاء في الحالة العامة. أي إذا كنت أكتب الخاصة الدالة "printf_better" الذي لديه نفس التوقيع كما printf، فإن المترجم لا يكشف إن وجدت الحجج مفقودة.

نصائح أخرى

وماذا يحدث يشبه هذا.

printf("%d", m);

في معظم أنظمة عنوان السلسلة سوف تحصل على دفع على المكدس، ثم 'm' كعدد (على افتراض أنه عدد صحيح / قصير / شار). ليس هناك تحذير لprintf يعلن أساسا كما 'int printf(const char *, ...);' - و... يعني "كل شيء مباح"

وهكذا منذ "كل شيء مباح" بعض أشياء غريبة تحدث عند وضع المتغيرات هناك. أي نوع لا يتجزأ أصغر من عدد صحيح يسير كما هو عدد صحيح - أشياء من هذا القبيل. إرسال أي شيء على الإطلاق على ما يرام أيضا.

في تنفيذ printf (أو على الأقل "بسيط" التنفيذ) سوف تجد استخدام va_list وva_arg (أسماء مقرها في وقت ما تختلف قليلا على التوافق). هذه هي ما يستخدم التنفيذ على المشي حول '...' جزء من قائمة وسيطة. المشكلة هنا هي أن هناك NO نوع التحقق. اذ لا يوجد اي نوع التحقق، سوف printf سحب بيانات عشوائية قبالة كومة التنفيذ عندما ينظر إلى ("%d") سلسلة التنسيق ويعتقد أن هناك من المفترض أن يكون 'int' المقبل.

واطلاق النار العشوائي في الظلام أن أقول أن وظيفة الدعوة التي أجريتها 'm-1' قبل printf ربما مرت كما انها PARM الثاني؟ هذا هو واحد من العديد من الاحتمالات - ولكن سيكون من المثير للاهتمام إذا كان هذا حدث ليكون هذا هو الحال. :)

وحظا سعيدا.

وبالمناسبة - (؟ دول مجلس التعاون الخليجي أعتقد) معظم المجمعات الحديثة لديها التحذيرات التي يمكن تمكين للكشف عن هذه المشكلة. الوبر لا، وكذلك على ما أعتقد. للأسف أعتقد مع VC تحتاج إلى استخدام / تحليل العلم بدلا من الحصول مجانا.

وأنها حصلت على عدد صحيح من المكدس.

http://en.wikipedia.org/wiki/X86_calling_conventions

وأنت تحدق في كومة. تغيير القيم محسن، وهذا قد يتغير. تغيير ترتيب الإعلانات المتغيرات الخاصة بك (وخاصة) m. جعل m متغير السجل. جعل m متغير عمومي.

وسترى بعض الاختلافات في ما يحدث.

وهذا هو مماثل لتجاوز سعة المخزن المؤقت الخارقة الشهيرة التي تحصل عند القيام التبسيط I / O.

وبينما أنا أشك بشدة هذا من شأنه أن يؤدي إلى انتهاك الذاكرة، وصحيح تحصل القمامة غير محددة.

هل وجدت <م> سلوك واحد. كان يمكن أن يكون <م> أي سلوك الآخرين، بما في ذلك الوصول إلى ذاكرة غير صالح.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top