2014-09-12 2 views
11
#include <stdio.h> 

int puts(const char* str) 
{ 
    return printf("Hiya!\n"); 
} 

int main() 
{ 
    printf("Hello world.\n"); 
    return 0; 
} 

इस कोड को आउटपुट "हिया!" जब दौड़ते हैं। क्या कोई समझा सकता है क्यों?क्या प्रिंटफ को सी प्रोग्राम में स्वचालित रूप से रखकर प्रतिस्थापित किया जा सकता है?

संकलन लाइन है: gcc main.c

संपादित करें: यह अब शुद्ध सी है, और किसी भी बाहरी सामान संकलन लाइन से हटा दिया गया।

+0

यह अनुकूलन कि जीसीसी के अनुकूलन विकल्प पर निर्भर नहीं करता है पर निर्भर करता है। – BLUEPIXY

+1

प्रश्न को 'c' के रूप में टैग किया गया है, हालांकि संकलक आमंत्रण से पता चलता है कि कोड को C++ के रूप में संकलित किया गया है। –

+2

हां, जीसीसी 'printf() 'से' puts()' तक एक साधारण निरंतर स्ट्रिंग प्रिंट को अनुकूलित कर सकता है, जैसा कि बाद में बेहतर प्रदर्शन करता है ... चूंकि आपने मानक लाइब्रेरी को स्थानीय प्रतीक के साथ बदल दिया है, इसलिए आप यही हैं प्राप्त। यदि आप -ओ 2 के बजाय -O0 का उपयोग करते हैं, तो आपको वास्तव में 'printf() ' – JohnH

उत्तर

12

है हाँ, एक संकलक puts के लिए एक बराबर कॉल द्वारा printf के लिए एक कॉल जगह ले सकती।

क्योंकि आपने मानक लाइब्रेरी फ़ंक्शन के समान नाम के साथ अपना स्वयं का फ़ंक्शन puts परिभाषित किया है, तो आपके प्रोग्राम का व्यवहार अपरिभाषित है।

संदर्भ: N1570 7.1.3:

निम्नलिखित subclauses में से किसी में बाहरी लिंकेज [इस puts भी शामिल है] हमेशा बाह्य संबंध के साथ पहचानकर्ता के रूप में उपयोग के लिए आरक्षित हैं के साथ सभी पहचानकर्ता।
...
कार्यक्रम की घोषणा की है या एक किस संदर्भ में उसे सुरक्षित रखा गया है (के रूप में 7.1.4 द्वारा अनुमति के अलावा अन्य) में एक पहचानकर्ता परिभाषित करता है, या किसी मैक्रो नाम के रूप में एक सुरक्षित पहचानकर्ता को परिभाषित करता है, तो व्यवहार अनिर्धारित रहता है।

आप अपने खुद के puts समारोह को हटाने और एक विधानसभा सूची की जांच, तो आप उत्पन्न कोड जहां स्रोत कोड में printf बुलाया में puts के लिए एक कॉल मिल सकती है। (मैंने देखा है कि जीसीसी इस विशेष अनुकूलन को निष्पादित करता है।)

+2

(अस्वीकरण: केवल होस्टेड कार्यान्वयन में) – Deduplicator

0

मुमकिन है, अपनी लाइब्रेरी के printf() कहते हैं कॉल()।

आपके रखरखाव() लाइब्रेरी संस्करण को बदल रहे हैं।

+6

दरअसल, 'printf' * * रनटाइम * पर 'puts' को कॉल नहीं कर रहा है, लेकिन * कंपाइलर *' printf' को 'puts' के साथ * compile-time * –

8

यह संकलक और अनुकूलन स्तर पर निर्भर करता है। GCC के नवीनतम संस्करणों की, कुछ सामान्य सिस्टम पर, कुछ अनुकूलन के साथ, इस तरह के एक अनुकूलन

आप जब संकलन चेतावनी सक्षम होना चाहिए ((puts के साथ एक सरल printf, जो AFAIU C99 की तरह कानूनी wrt मानकों है की जगह) कर पा रहे हैं जैसे gcc -Wall -g साथ संकलित करने के लिए पहली कोशिश है, तो gdb साथ डिबग, तो जब आप अपने कोड के साथ विश्वास है gcc -Wall -O2 साथ यह संकलन)

Btw, फिर से परिभाषित करने puts वास्तव में बहुत बदसूरत है, जब तक आप उद्देश्य पर यह कर (यानी कोडिंग कर रहे हैं अपने अपनी सी पुस्तकालय, और फिर आपको मानकों का पालन करना होगा)। आपको कुछ undefined behavior मिल रहे हैं (यूबी के संभावित परिणामों के बारे में this answer भी देखें)। असल में आपको मानक में उल्लिखित नामों को फिर से परिभाषित करने से बचना चाहिए, जब तक कि आप वास्तव में वास्तव में अच्छी तरह से नहीं जानते कि आप क्या कर रहे हैं और कंपाइलर के अंदर क्या हो रहा है।

इसके अलावा, यदि आप gcc -Wall -static -O main.c -o yourprog जैसे स्थिर लिंकिंग के साथ संकलित हैं तो मैं शर्त लगाऊंगा कि लिंकर शिकायत करेगा (puts की एकाधिक परिभाषा के बारे में)।

लेकिन IMNSHO अपने कोड सादा गलत है, और आपको लगता है कि पता है।

इसके अलावा, आप, उदाहरण के लिए कोडांतरक प्राप्त करने के लिए संकलन कर सकता है gcc -fverbose-asm -O -S के साथ; और तुम भी gcc पूछना gcc -fdump-tree-all -O जो आप समझ gcc कर रहा है मदद कर सकता है के साथ एक बहुत "डंप" फ़ाइलों की गिर करने के लिए, हो सकता है। , किसी भी libc की printf नियमित क्रम प्रिंट प्रारूप स्ट्रिंग (निपटने %s आदि ... विशेष रूप से) पर "की व्याख्या करने के लिए" है:

फिर, यह विशेष रूप से अनुकूलन वैध और बहुत उपयोगी है यह अभ्यास में काफी धीमी है। एक अच्छा कंपाइलर printf (और puts के साथ प्रतिस्थापित) को कॉल करने से बचने में सही है।

BTW gcc केवल कि अनुकूलन कर संकलक नहीं है। clang भी यह करता है।

इसके अलावा, अगर आप

gcc -ffreestanding -O2 almo.c -o almo 

साथ संकलन almo कार्यक्रम Hello world.


से पता चलता है आप एक और कल्पना और आश्चर्य की बात अनुकूलन चाहते हैं, gcc -O2 -fverbose-asm -S bas.c साथ

// file bas.c 
#include <stdlib.h> 
int f (int x, int y) { 
    int r; 
    int* p = malloc(2*sizeof(int)); 
    p[0] = x; 
    p[1] = y; 
    r = p[0]+p[1]; 
    free (p); 
    return r; 
} 

संकलन करने की कोशिश फिरमें देखें; आपको malloc या free पर कोई कॉल नहीं दिखाई देगा (वास्तव में, call मशीन निर्देश उत्सर्जित है) और फिर, gcc अनुकूलित करने के लिए सही है (और clang भी करता है)!

पीएस: जीएनयू/लिनक्स/डेबियन/सिड/x86-64; gcc, संस्करण 4.9.1 है clang संस्करण 3.4.2

+0

अच्छा बिंदु पर प्रतिस्थापित करने का अधिकार है; बस जीसीसी के साथ कोशिश की, तो सवाल खड़ा है, और जवाब के लिए धन्यवाद। कुछ और जांच करेंगे और बाद में जवाब स्वीकार करेंगे। :) – Almo

+0

मुझे पता है कि यह गलत है। मैं उत्सुक था कि यह ऐसा क्यों करता है। – Almo

+0

वाह यह एक बहुत अच्छा है (फैंसी और surprizing अनुकूलन) – Almo

1

अपने निष्पादन योग्य पर ltrace आज़माएं। आप देखेंगे कि printf को संकलक द्वारा puts कॉल द्वारा प्रतिस्थापित किया गया है। इस तरह से आप printf

कहा जाता है इस पर एक दिलचस्प पढ़ने here

+0

@navigaid संकेत देने के लिए धन्यवाद। मैंने जवाब संपादित किया। –

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

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