2010-06-16 14 views
5

में तर्कों का मूल्यांकन करने के लिए डेल्फी कंपाइलर निर्देश मैथपास से IFThen फ़ंक्शन का उपयोग करके मैं वास्तव में इस डेल्फी दो लाइनर से प्रभावित था। हालांकि, यह पहले डीबी.रेटर्नफिल्डआई का मूल्यांकन करता है, जो दुर्भाग्यपूर्ण है क्योंकि मुझे पहला रिकॉर्ड प्राप्त करने के लिए डीबी को कॉल करने की आवश्यकता है।रिवर्स

DB.RunQuery('select awesomedata1 from awesometable where awesometableid = "great"'); 
result := IfThen(DB.First = 0, DB.ReturnFieldI('awesomedata1')); 

(एक व्यर्थ स्पष्टीकरण के रूप में है, क्योंकि मैं इतने सारे अच्छे जवाब पहले से ही मिल गया है। मुझे लगता है कि 0 कोड है कि रिटर्न DB.First अगर यह उस में कुछ मिला है है उल्लेख करना भूल गया, भावना बना दिया है नहीं हो सकता है अन्यथा)

स्पष्ट रूप से यह इतना बड़ा सौदा नहीं है, क्योंकि मैं इसे पांच मजबूत लाइनर के साथ काम कर सकता हूं। लेकिन मुझे इसके लिए काम करने की ज़रूरत है डेल्फी के लिए पहले डीबी का मूल्यांकन करना। सबसे पहले और डीबी। रीटरफिल्डीआई दूसरा। मैं गणित को बदलना नहीं चाहता हूं और मुझे नहीं लगता कि यह मुझे ओवरलोडेड बनाने के लिए वारंट करता है क्योंकि 16 मिनट की तरह काम करता है।

बस मुझे यह बताएं कि कंपाइलर निर्देश क्या है, अगर ऐसा करने का कोई बेहतर तरीका है, या यदि ऐसा करने का कोई तरीका नहीं है और जिसकी प्रक्रिया डीबी को बुलाती है और सबसे पहले अंधेरे से पहली चीज़ को पुनः प्राप्त करें वह पाता है एक असली प्रोग्रामर नहीं है।

+6

यहां तक ​​कि अगर कोई संभावना है - ऐसा मत करो! यदि आपको पहले होने के लिए 'फर्स्ट' कॉल की आवश्यकता है, तो उसे इस तरह कोड करें। इस स्थिति में आईएमएचओ केवल एक स्पष्ट 'if' उचित है। –

+0

मैं आपकी विनम्र राय को ध्यान में रखता हूं, लेकिन क्या आपको नहीं लगता कि IfThen फ़ंक्शन के साथ शुरू करने के लिए पीछे की ओर है? यदि यह अंत में उस वैकल्पिक पैरामीटर के लिए नहीं था, तो यह हमेशा ifThen (TrueResult, FalseResult, BooleanFunction) कहने के लिए और अधिक उपयोगी होगा। आपके तर्क से आप कहेंगे "अगर (functionA और functionB) तो अंत शुरू करें;" हमेशा लिखा जाना चाहिए "अगर फंक्शंस तो फ़ंक्शनब फिर समाप्त होता है;" ? –

+0

जरूरी नहीं है, क्योंकि बूलियन शॉर्टकट मूल्यांकन अच्छी तरह से जाना जाता है जबकि फ़ंक्शन तर्कों का मूल्यांकन आदेश नहीं है। यदि तब आम तौर पर बेकार है क्योंकि यह ** ** ** ** ** ** ** का मूल्यांकन करता है जो मेरे अनुभव में नहीं चाहता था - मैं ज्यादातर ** ** ** सत्य अभिव्यक्ति ** या ** गलत अभिव्यक्ति निष्पादित करना चाहता हूं । –

उत्तर

12

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

function GetFirstIfAvailable(DB: TDatabaseObject; const FieldName: string): Integer; 
begin 
    if DB.First = 0 then 
    Result := DB.ReturnFieldI(FieldName) 
    else 
    Result := 0; 
end; 

आपका मूल कोड शायद नहीं किया गया है जैसे आप चाहते हैं, भले ही मूल्यांकन के क्रम भिन्न थे। भले ही DB.First शून्य के बराबर नहीं था, तो ReturnFieldI पर कॉल का मूल्यांकन अभी भी किया जाएगा। उन सभी कार्यों का उपयोग करने से पहले सभी वास्तविक मानकों का पूरी तरह से मूल्यांकन किया जाता है।

बदलना Math.pas आपको वैसे भी मदद नहीं करेगा। यह नियंत्रित नहीं करता है कि इसके वास्तविक मानकों का मूल्यांकन किस क्रम में किया जाता है। जब तक उन्हें यह देखता है, तब तक उनका पहले से ही एक बूलियन मान और एक पूर्णांक का मूल्यांकन किया जा चुका है; वे अब निष्पादन योग्य अभिव्यक्ति नहीं हैं।


कॉलिंग सम्मेलन मूल्यांकन आदेश को प्रभावित कर सकता है, लेकिन अभी भी कोई गारंटी नहीं है। ऑर्डर जो पैरामीटर को स्टैक पर धक्का दिया जाता है, उस क्रम से मेल खाने की आवश्यकता नहीं होती है जिसमें वे मान निर्धारित किए गए थे।दरअसल, अगर आपको लगता है कि स्टडकॉल या सीडीईएल आपको अपना वांछित मूल्यांकन ऑर्डर (बाएं से दाएं) देता है, तो उनका मूल्यांकन रिवर्स ऑर्डर में किया जा रहा है।

पास्कल कॉलिंग सम्मेलन स्टैक पर बाएं से दाएं तर्क पारित करता है। इसका मतलब है कि बाएंतम तर्क स्टैक के नीचे एक है, और दाएं पते के ठीक नीचे, दाएं दाएं शीर्ष पर है।

  1. जिस तरह से आप उम्मीद करते हैं, जो कि प्रत्येक तर्क का मूल्यांकन किया और तुरंत धकेल दिया जाता है: IfThen समारोह सम्मेलन बुला का उपयोग किया जाता है, वहाँ कई तरीके संकलक कि ढेर लेआउट प्राप्त कर सकते हैं

    push (DB.First = 0) 
    push DB.ReturnFieldI('awesomedata1') 
    call IfThen 
    
  2. तर्क मूल्यांकन दाएँ-से-बाएँ और जब तक वे धक्का दिया रहे temporaries में परिणाम की दुकान:

    tmp1 := DB.ReturnFieldI('awesomedata1') 
    tmp2 := (DB.First = 0) 
    push tmp2 
    push tmp1 
    call IfThen 
    
  3. Allo cate ढेर अंतरिक्ष पहले, और में किसी भी क्रम सुविधाजनक है का मूल्यांकन:

    sub esp, 8 
    mov [esp], DB.ReturnFieldI('awesomedata1') 
    mov [esp + 4], (DB.First = 0) 
    call IfThen 
    

सूचना है कि IfThenसभी तीन मामलों में एक ही क्रम में तर्क मान प्राप्त करता है, लेकिन कार्यों जरूरी में कहा जाता है नहीं कर रहे हैं वह आदेश

डिफ़ॉल्ट रजिस्टर कॉलिंग सम्मेलन भी बाएं से दाएं तर्क पास करता है, लेकिन पहले तीन तर्क रजिस्टरों में पास किए जाते हैं। रजिस्ट्रार तर्कों को पारित करने के लिए उपयोग किए जाते हैं, हालांकि, इंटरमीडिएट अभिव्यक्तियों का मूल्यांकन करने के लिए आमतौर पर उपयोग किए जाने वाले रजिस्टरों भी होते हैं। DB.First = 0 का नतीजा ईएक्स रजिस्टर में पारित करने की आवश्यकता है, लेकिन संकलक को ReturnFieldI पर कॉल करने और First पर कॉल करने के लिए पंजीकरण करने की भी आवश्यकता है। यह शायद एक छोटे से अधिक इस तरह प्रथम, द्वितीय समारोह का मूल्यांकन करने के लिए सुविधाजनक था:

call DB.ReturnFieldI('awesomedata1') 
mov [ebp - 4], eax // store result in temporary 
call DB.First 
test eax, eax 
setz eax 
mov edx, [ebp - 4] 
call IfThen 

का कहना है के लिए एक और बात यह है कि अपने पहले तर्क एक यौगिक अभिव्यक्ति है। एक फ़ंक्शन कॉल और तुलना है। गारंटी देने के लिए कुछ भी नहीं है कि उन दो भागों को लगातार प्रदर्शन किया जाता है। संकलक को First और ReturnFieldI पर कॉल करके पहली बार फ़ंक्शन कॉल से बाहर निकल सकता है, और इसके बाद First शून्य के विरुद्ध वापसी मान की तुलना करें।

+0

यह वही है जो मैं करता हूं लेकिन तीसरे वैकल्पिक पैरामीटर के साथ जो मुझे डिफ़ॉल्ट वापसी मान बदलने की इजाजत देता है। –

+0

आप उपरोक्त फ़ंक्शन में अपेक्षित कार्य करने के लिए एक वैकल्पिक पैरामीटर जोड़ सकते हैं। –

+0

ओह आप सही हैं, मेरा कोड काम करेगा, लेकिन किसी भी तार्किक कारण के लिए नहीं। हालांकि मुझे समझ में नहीं आ रहा है, क्यों मैं पैरामीटर में कार्यों का मूल्यांकन करने के लिए सीडीईसीएल और एसटीडीकॉल पर भरोसा नहीं कर सकता हूं, जैसा कि वे कहते हैं कि वे पास होंगे। मान लीजिए कि मैं 100% डेल्फी हूं, ट्रिकिंग में क्या नुकसान है अभिव्यक्तियों का मूल्यांकन करने में संकलक जिस तरह से मुझे सुविधाजनक लगता है? –

1

क्या आप अपनी क्वेरी को केवल एक परिणाम के लिए नहीं बदल सकते हैं, इसलिए 'फर्स्ट' कमांड करने से बचें? बस की तरह है:

SELECT TOP 1 awesomedata1 from awesometable 

पहुँच ...

0

AFAIK वहाँ इस पर नियंत्रण करने के लिए कोई संकलक निर्देश है। जब तक आप stdcall/cdecl/safecall सम्मेलनों का उपयोग नहीं करते हैं, पैरामीटर को स्टैक पर बाएं से दाएं पास किया जाता है, लेकिन क्योंकि डिफ़ॉल्ट रजिस्टर सम्मेलन रजिस्टरों में पैरामीटर भी पास कर सकता है, ऐसा हो सकता है कि पैरामीटर की गणना बाद में एक रजिस्टर में की जाती है कॉल से ठीक पहले। और क्योंकि अर्हता प्राप्त करने वाले पैरामीटर के लिए केवल रजिस्टर ऑर्डर तय किया जाता है (ईएक्स, ईडीएक्स, ईसीएक्स), रजिस्ट्रार किसी भी क्रम में लोड किया जा सकता है। आप एक "पास्कल" कॉलिंग कन्वेंशन को मजबूर करने की कोशिश कर सकते हैं (वैसे भी आपको फ़ंक्शन को फिर से लिखना होगा), लेकिन यदि आईएमएचओ इस तरह के कोड पर भरोसा करना हमेशा खतरनाक होता है, तो संकलक मूल्यांकन के आदेश की स्पष्ट गारंटी नहीं दे सकता है। और एक मूल्यांकन आदेश लागू करने से उपलब्ध अनुकूलन की संख्या बहुत कम हो सकती है।

3

calling convention उनके मूल्यांकन के तरीके को प्रभावित करता है।
इस पर नियंत्रण करने के लिए एक कंपाइलर परिभाषित नहीं है।

Pascal कॉलिंग सम्मेलन है जिसे आपको इस व्यवहार को प्राप्त करने के लिए उपयोग करना होगा।

हालांकि मैं व्यक्तिगत रूप से कभी इस तरह के व्यवहार पर निर्भर नहीं होगा।

निम्नलिखित उदाहरण प्रोग्राम दर्शाता है कि यह कैसे काम करता है।

program Project2; 
{$APPTYPE CONSOLE} 
uses SysUtils; 

function ParamEvalTest(Param : Integer) : Integer; 
begin 
    writeln('Param' + IntToStr(Param) + ' Evaluated'); 
    result := Param; 
end; 

procedure TestStdCall(Param1,Param2 : Integer); stdCall; 
begin 
    Writeln('StdCall Complete'); 
end; 

procedure TestPascal(Param1,Param2 : Integer); pascal; 
begin 
    Writeln('Pascal Complete'); 
end; 

procedure TestCDecl(Param1,Param2 : Integer); cdecl; 
begin 
    Writeln('CDecl Complete'); 
end; 

procedure TestSafecall(Param1,Param2 : Integer); safecall; 
begin 
    Writeln('SafeCall Complete'); 
end; 

begin 
    TestStdCall(ParamEvalTest(1),ParamEvalTest(2)); 
    TestPascal(ParamEvalTest(1),ParamEvalTest(2)); 
    TestCDecl(ParamEvalTest(1),ParamEvalTest(2)); 
    TestSafeCall(ParamEvalTest(1),ParamEvalTest(2)); 
    ReadLn; 
end. 

इसके लिए आपको अपने स्वयं के इफ्टेन फ़ंक्शन लिखने की आवश्यकता होगी।

यदि आप वास्तव में यह एक लाइनर बनना चाहते हैं तो आप वास्तव में डेल्फी में ऐसा कर सकते हैं। मुझे लगता है कि यह बदसूरत लग रहा है।

If (DB.First = 0) then result := DB.ReturnFieldI('awesomedata1') else result := 0; 
+3

नहीं, यह कॉलिंग सम्मेलन द्वारा नियंत्रित नहीं है। कॉलिंग कन्वेंशन नियंत्रित करता है कि पैरामीटर को स्टैक पर किस क्रम में रखा गया है, या मूल्यों को किस रजिस्टर्ड में संग्रहीत किया जाता है, लेकिन यह मूल्यांकन आदेश को नियंत्रित नहीं करता है। (यह * मूल्यांकन आदेश को प्रभावित कर सकता है, लेकिन यह नियंत्रण के समान नहीं है।) –

+0

मान्य बिंदु, मैंने इसे प्रतिबिंबित करने के लिए अपनी प्रतिक्रिया अपडेट की है। –

+0

मैंने इसे एक मिनट के लिए सही के रूप में चिह्नित किया, लेकिन रॉब ने वास्तव में सिर पर नाखून मारा जब उसने कहा कि डीबी .returnfieldI का मूल्यांकन अभी भी किया जाएगा। मैं वास्तव में नहीं चाहता कि ऐसा होने पर डीबी.फर्स्ट <> 0. स्रोत कोड के लिए धन्यवाद, यह वास्तव में उन सम्मेलनों के बीच मतभेदों को स्पष्ट करने में मदद करता है। –

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