मुझे एक विरासत कोड दिया गया है, जहां किसी ने लापरवाही से double मान दिए हैं से int वेरिएबल जैसे:

int a = 10;
double b = 20;
a = b;

अब इससे छुटकारा पाने के लिए

चेतावनी C4244: '=': 'डबल' से 'इंट' में रूपांतरण, डेटा की संभावित हानि

चेतावनियों, मैंने कोड को अपस्ट्रीम संपादित करने और अनावश्यक double चर से छुटकारा पाने की कोशिश की, लेकिन यह बहुत गन्दा निकला!

मैं कास्टिंग का भी उपयोग कर सकता था:

a = (int) b;

लेकिन वास्तव में इस बात की कोई गारंटी नहीं है कि b एक पूर्णांक की सीमा के भीतर होगा। मैंने एक सहायक कार्य करने के बारे में सोचा:

int safeD2I(double inputVar){
  if ((inputVar < INT_MAX) && (INT_MIN < inputVar)){
    return (int) inputVar;
  } else {
    exit(-1);
  }
}

लेकिन मुझे यकीन नहीं है कि यह सबसे अच्छा कार्यान्वयन है या नहीं। मैं सोच रहा था कि क्या इस मुद्दे को संभालने का कोई और विहित तरीका है?

जो मैं चाहता हूं:

  • यदि b चर पूर्णांक सीमा से बाहर है, तो प्रोग्राम तुरंत बंद हो जाता है
  • टर्मिनल पर एक त्रुटि संदेश प्रिंट करता है जो दर्शाता है कि यह समस्या होने पर विशिष्ट लाइन और समय।

आपके समर्थन के लिए अग्रिम धन्यवाद।

2
Foad 22 मार्च 2020, 18:12
1
वैसे आपका कोड किसी भी मान को पास कर देगा जैसा कि अभी है। आपको || के बजाय && चाहिए।
 – 
CherryDT
22 मार्च 2020, 18:16
यदि आप यह देखने के लिए कोई विधि खोज रहे हैं कि क्या कोई डेटा हानि हुई है, तो ऐसा लगता है कि आप केवल असाइनमेंट करना चाहते हैं और फिर तुलना करना चाहते हैं। जैसे if( (double)a - b > epsilon) ...
 – 
William Pursell
22 मार्च 2020, 18:16
1
यदि किसी सरणी को अनुक्रमित करना रूपांतरण का एकमात्र कारण है, तो आप बहुत बेहतर स्थिति में हैं। एक फ़ंक्शन बनाएं जो आपको double द्वारा अनुक्रमित सरणी तक पहुंचने देता है, वहां सभी डबल-टू-साइज_टी रूपांतरणों को स्थानीयकृत करता है, और आपके विशिष्ट सरणी के लिए एक सीमा चेकर लागू करता है, क्योंकि MAX_INT अक्सर एक से बहुत बड़ा होता है सूचकांक, भले ही यह बिना किसी समस्या के int में फिट बैठता हो।
 – 
Sergey Kalinichenko
22 मार्च 2020, 18:42
1
आपकी सी प्रवीणता के आधार पर, मैं इस कोड में कोई भी अनावश्यक या "क्लीनअप" परिवर्तन करने के लिए बहुत सावधान होगा। आपके द्वारा ठीक किए जाने से कहीं अधिक टूटने की संभावना है। केवल वहीं परिवर्तन करें जहां आपने विश्लेषण किया है ताकि यह निर्धारित किया जा सके कि एक सक्रिय बग है, और चीजों को ठीक करने के लिए रिफैक्टर न करें। सरल प्रत्यक्ष इनलाइन सुधार करें।
 – 
R.. GitHub STOP HELPING ICE
22 मार्च 2020, 18:49
1
देखें क्या डबल से इंट में रूपांतरण हो सकता है पोर्टेबल C में लिखा जाए। यह अपरिभाषित व्यवहार से बचते हुए सीमा के मुद्दे को संबोधित करता है, लेकिन, एक बार जब आप इससे निपट लेते हैं, तो अंश के मुद्दे से निपटना आसान हो जाता है।
 – 
Eric Postpischil
22 मार्च 2020, 18:57

2 जवाब

सबसे पहले, कोड के साथ स्वाभाविक रूप से गलत या असुरक्षित कुछ भी नहीं है। असाइनमेंट द्वारा रूपांतरण सी भाषा का पूरी तरह से वैध हिस्सा है। यदि यह लीगेसी कोड है जहां आप पता नहीं को सुरक्षित रूप से किया जा रहा है या नहीं, तो आपको इसे निर्धारित करने के लिए विश्लेषण करने की आवश्यकता है।

यदि आप पाते हैं कि आपको संभावित आउट-ऑफ-बाउंड मानों को पकड़ने की आवश्यकता है (जो int में परिवर्तित होने पर अपरिभाषित व्यवहार (!!) उत्पन्न करते हैं), तो आपका कोड गलत और नाजुक दोनों है। तुलना जैसे:

double x;
...
if (x < INT_MAX) ...

तुलना के लिए INT_MAX को double टाइप करने के लिए मजबूर करें। व्यवहार में ऐसी दुनिया में जहां double आईईईई डबल है और int 32-बिट है, यह सुरक्षित होता है, लेकिन उदाहरण के लिए यह असुरक्षित होगा यदि आपने double को float, चूंकि 32-बिट INT_MAX एकल-परिशुद्धता float में प्रतिनिधित्व योग्य नहीं है। मान को गोल किया जाएगा, और फिर गोलाई के बाद तुलना की जाएगी।

अब, यह पता चला है कि आपके पास एक-एक-एक त्रुटि भी है (<= INT_MAX, < INT_MAX नहीं, जो कि सीमा में है) साथ ही साथ गलत तर्क (|| के बजाय &&) इसलिए गोलाई वास्तव में उसी के हिस्से को ठीक कर देगी। लेकिन इस पर निर्भर रहना ठीक नहीं है। इसके बजाय आपको दो की शक्ति का निर्माण करने की आवश्यकता है, जिसकी तुलना आप कर सकते हैं, इसलिए फ्लोटिंग पॉइंट में बदलना सुरक्षित है। उदाहरण के लिए:

  • if (x < 2.0*(INT_MAX/2+1) && x >= INT_MIN)
  • if (-x > (-INT_MAX-1) && x >= INT_MIN)
  • if (-x > INT_MIN && x >= INT_MIN)

ये सभी मानते हैं कि INT_MIN वास्तव में दो की शक्ति है (पूर्ण श्रेणी के दो पूरक) जो एक उचित वास्तविक दुनिया की धारणा है और C2x + द्वारा आवश्यक है। यदि आप अधिक व्यापकता चाहते हैं तो यह अधिक काम है।

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

5
R.. GitHub STOP HELPING ICE 22 मार्च 2020, 18:51
धन्यवाद। इस समय आपके उत्तर को समझना मेरे लिए थोड़ा कठिन है। आपने जो कहा है, मैं उसका अध्ययन करूंगा और यदि मेरे पास और प्रश्न हैं तो मैं यहां वापस आऊंगा।
 – 
Foad
22 मार्च 2020, 18:39
2
ध्यान दें, @Foad, एक अनुभवी प्रोग्रामर के लिए भी एक अच्छा अभ्यास जब मौजूदा कोड को उसके व्यवहार को बदले बिना संशोधित करने का काम सौंपा जाता है, तो उस कोड के स्वचालित परीक्षण तैयार करना होता है जिसे संशोधित किया जाना है। ये यथासंभव पूर्ण होने चाहिए, सामान्य, चरम और त्रुटि मामलों को विस्तार से कवर करना चाहिए। परीक्षणों को मूल कोड के विरुद्ध मान्य किया जा सकता है, और संशोधित कोड को परीक्षणों के विरुद्ध मान्य किया जा सकता है। इसे अच्छी तरह से करना न तो आसान है और न ही आसान, लेकिन तत्काल कोड संशोधन कार्य पूरा होने के बाद भी परिणाम कोड आधार के लिए एक मूल्यवान अतिरिक्त है।
 – 
John Bollinger
22 मार्च 2020, 19:01
योजना में परीक्षण सुनिश्चित है। शायद Google परीक्षणों का उपयोग करें। लेकिन अभी के लिए, मैं यह सुनिश्चित करना चाहता हूं कि मैं संकलन चेतावनी से छुटकारा पा सकूं। और कोड के बारे में कोई चिंता नहीं है। यह एक कांटा है। और मैं विकास शाखा की एक शाखा पर काम कर रहा हूँ। इसलिए अगर कुछ भी गलत होता है तो मेरे पास मास्टर सुरक्षित है।
 – 
Foad
22 मार्च 2020, 19:07
अपने स्वयं के लिए कंपाइलर चेतावनियों से छुटकारा पाने के लिए सेट करना, इस बात पर कोई ध्यान नहीं देना कि कोड वास्तव में क्या कर रहा है और क्या आपके परिवर्तन टूट रहे हैं, चीजों को तोड़ने के लिए एक निश्चित नुस्खा है। ऐसा नहीं है कि कंपाइलर चेतावनियों का उपयोग कैसे किया जाना है।
 – 
R.. GitHub STOP HELPING ICE
22 मार्च 2020, 19:45
x >= INT_MIN गलत तरीके से विफल हो जाता है x मान INT_MIN से कम 1.0 से कम। जब INT_MIN 2 का पूरक है, x - INT_MIN > -1.0 उसे कवर करता है।
 – 
chux - Reinstate Monica
22 मार्च 2020, 22:36

डबल को इंट में बदलने का सुरक्षित तरीका क्या है?

if ((inputVar < INT_MAX) && (INT_MIN < inputVar)){ किनारे के मामलों को विफल करता है।

गलत किनारों के रूप में यह अधिक पसंद है, लेकिन बिल्कुल (inputVar < INT_MAX + 1) && (INT_MIN - 1 < inputVar) जैसा नहीं है

some_FP < SOME_INT_MAX जैसे कोड से सावधान रहें क्योंकि SOME_INT_MAX पूर्णांक प्रकार के कारण आवश्यक FP मान में परिवर्तित नहीं हो सकता है, जिसमें FP वाले की तुलना में अधिक सटीकता हो सकती है। यह int, double के साथ आमतौर पर कोई समस्या नहीं है।


जांचें कि क्या double, (INT_MIN-1 .... INT_MAX+1)1 की सीमा के भीतर है। नोट () और नहीं []।

यदि नहीं, तो अपने चयन के कुछ परिभाषित तरीके से त्रुटि करें या संभालें।

ठेठ 2 के पूरक को मानते हुए, लेकिन double की सटीकता को int से अधिक नहीं मानते (कोड को float, long long में माइग्रेट करने के लिए अधिक उपयोगी), कुछ नमूना कोड:

// FP version of INT_MAX + 1.0 
// Avoid direct (INT_MAX + 1.0) as that can have precision woes
#define DBL_INTMAX_P1 ((INT_MAX/2 + 1)*2.0)

int X_int_from_double(double x) {
  // Coded to insure NAN fails the if()
  if (!(x - INT_MIN > -1.0 && x < DBL_INTMAX_P1)) {
    errno = ERANGE;
    fprintf(stderr, "Error in %s,  %.*e too large\n", __func__, DBL_DECIMAL_DIG - 1, x);

    exit(EXIT_FAILURE);
    // or additional code to handle conversion in some specified manner
    // Example: assuming "wrap"
    if (!isfinite(x)) {
      if (!isnan(x)) return 0;
      if (x > 0) return INT_MAX;
      else return INT_MIN; 
    }
    modf(x, &x); // drop fraction
    x = fmod(x, DBL_INTMAX_P1*2);
    if (x >= DBL_INTMAX_P1) x -= DBL_INTMAX_P1*2;
    else if (x < -DBL_INTMAX_P1) x += DBL_INTMAX_P1*2;
  }
  return (int) x;
}

उस लाइन को रिकॉर्ड करने के लिए जहां यह विफल हुआ, लाइन नंबर पास करने के लिए मैक्रो पर विचार करें।

int X_int_from_double(double x, unsigned);
#define DOUBLE_TO_INT(x) X_int_from_double((x), __LINE__)

1

1
chux - Reinstate Monica 22 मार्च 2020, 23:10