मैं काफी हद तक यह मान रहा हूं कि यह एक बेवकूफी भरा सवाल है ... लेकिन मैं वास्तव में इसका जवाब नहीं ढूंढ सकता। तो मैं यह यहाँ पूछ रहा हूँ।

निहित प्रकार की कास्टिंग के बारे में सीखने के उद्देश्य से, मैं सी पर निम्नलिखित कोड चला रहा हूं।

#include <stdio.h>

int main()
{
    unsigned char i;
    char cnt = -1;

    int a[255];

    for (int k = 0; k < 255; k++)
    {
        a[k] = k;
    }
    for (i = cnt - 2; i < cnt; i--)
    {
        a[i] += a[i + 1];
        printf("%d\n", a[i]);
    }

    return 0;
}

जब मैंने यह कार्यक्रम चलाया, तो कुछ नहीं हुआ।

मैं यह पता लगाने में सक्षम था कि पहले पुनरावृत्ति पर फॉर-लूप की लूप स्थिति झूठी थी, इसलिए प्रोग्राम तुरंत फॉर-लूप से बाहर निकल गया।

हालाँकि, मुझे इसका कारण नहीं पता है।

जहां तक ​​​​मुझे पता है, सी विभिन्न प्रकारों के साथ चर निर्दिष्ट या तुलना करते समय निहित कास्टिंग करता है। इसलिए मैंने सोचा कि i = cnt - 2 पर, माइनस ऑपरेशन मान -3 बनाता है, और फिर निहित कास्टिंग मुझे मान 253 के साथ असाइन करता है।

फिर, क्या शर्त i < cnt सच नहीं होनी चाहिए (हस्ताक्षरित और अहस्ताक्षरित चार की तुलना के कारण cnt की एक और निहित कास्टिंग द्वारा) 253 255 से छोटा है?

अगर नहीं है तो यह झूठ क्यों है? क्या ऐसा कुछ है जो मुझे याद आया या क्या कोई अपवाद है जो मुझे नहीं पता?

2
asdfqwerzxcv215 2 सितंबर 2021, 14:55

2 जवाब

सबसे बढ़िया उत्तर

आपका सवाल बिल्कुल भी बेहूदा नहीं है। आप समाधान के करीब थे: i को मान -3 सौंपा गया है, लेकिन i, unsigned char के प्रकार में निहित रूपांतरण, मान को 253 में बदल देता है। .

अधिक सटीक व्याख्या के लिए, आपके परीक्षण कोड में कई समस्याएं हैं:

  • char को प्लेटफ़ॉर्म और कंपाइलर कॉन्फ़िगरेशन के आधार पर हस्ताक्षरित या अहस्ताक्षरित किया जा सकता है, इसलिए char cnt = -1; मान -1 या 255 को cnt, या यहां तक ​​कि कुछ अन्य में संग्रहीत कर सकता है। मान अगर char अहस्ताक्षरित है और इसमें 8 बिट से अधिक हैं।

  • for (i = cnt - 2; i < cnt; i--) का व्यवहार इस बात पर भी निर्भर करता है कि char डिफ़ॉल्ट रूप से हस्ताक्षरित है या अहस्ताक्षरित:

    • सभी मामलों में, परीक्षण i < cnt का मूल्यांकन किया जाता है, दोनों ऑपरेंड को int (या unsigned int में परिवर्तित किया जाता है, जहां दुर्लभ मामले में sizeof(int)==1)। अगर int, char और unsigned char के सभी मानों का प्रतिनिधित्व कर सकता है, तो यह रूपांतरण मान नहीं बदलता है।

    • यदि char अहस्ताक्षरित है और इसमें 8 बिट हैं, cnt का मान 255 है, तो i को मान 253 के साथ प्रारंभ किया गया है और लूप i के साथ 253 से नीचे 0 तक 254 बार चलता है, फिर i-- मान 255 को फिर से i में स्टोर करता है, जिसके लिए परीक्षण i < cnt असत्य का मूल्यांकन करता है। लूप प्रिंट करता है 507, फिर 759, ... 32385

    • यदि char हस्ताक्षरित है और उसमें 8 बिट हैं, जैसा कि संभवतः आपके सिस्टम पर होता है, cnt का मान -1 है और i के साथ आरंभ किया गया है मान -3 को unsigned char में बदल दिया गया, जो कि 253 है। प्रारंभिक परीक्षण i < cnt का मूल्यांकन 253 < -1 के रूप में किया जाता है, जो गलत है, जिससे लूप बॉडी को तुरंत छोड़ दिया जाता है।

आप कंपाइलर को उचित फ़्लैग (जैसे: gcc -funsigned-char) देकर डिफ़ॉल्ट रूप से char को अहस्ताक्षरित होने के लिए बाध्य कर सकते हैं और परीक्षण कर सकते हैं कि व्यवहार कैसे बदलता है। Godbolt के कंपाइलर एक्सप्लोरर का उपयोग करके, आप देख सकते हैं कि gcc 0 को वापस करने के लिए केवल 2 निर्देश जेनरेट करता है हस्ताक्षरित (डिफ़ॉल्ट) मामला और अहस्ताक्षरित मामले में अपेक्षित आउटपुट।

3
Eric Postpischil 2 सितंबर 2021, 13:17

शुरुआत के लिए मान लेते हैं कि प्रकार char प्रकार के रूप में व्यवहार करता है signed char

हालत में

i < cnt

पूर्णांक प्रचार के कारण दोनों ऑपरेंड परोक्ष रूप से int प्रकार में परिवर्तित हो जाते हैं।

सी स्टैंडर्ड से (6.5.8 रिलेशनल ऑपरेटर्स)

3 यदि दोनों ऑपरेंड का अंकगणितीय प्रकार है, सामान्य अंकगणित रूपांतरण किए जाते हैं।

और (6.3.1.8 सामान्य अंकगणितीय रूपांतरण)

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

... अन्यथा, पूर्णांक प्रचार दोनों ऑपरेंड पर निष्पादित किए जाते हैं। फिर निम्नलिखित नियम प्रचारित ऑपरेंड पर लागू होते हैं:

यदि दोनों ऑपरेंड का प्रकार समान है, तो आगे रूपांतरण की आवश्यकता नहीं है

और (6.3.1.1 बूलियन, वर्ण और पूर्णांक)

  1. ...यदि कोई इंट मूल प्रकार के सभी मानों का प्रतिनिधित्व कर सकता है (प्रतिबंधित के रूप में) चौड़ाई से, बिट-फ़ील्ड के लिए), मान को एक इंट में बदल दिया जाता है; अन्यथा, इसे एक अहस्ताक्षरित int में बदल दिया जाता है। इन्हें कहा जाता है पूर्णांक प्रचार

इस प्रकार पूर्णांक पदोन्नति के बाद i का धनात्मक मान 0000 0000 1111 1101 के रूप में दर्शाया गया है, जो ऋणात्मक मान 1111 1111 1111 1111 से अधिक होगा।

तो लूप के लिए स्थिति एक बार तार्किक असत्य का मूल्यांकन करती है क्योंकि int प्रकार का सकारात्मक मान 253 प्रकार int के ऋणात्मक मान -1 से अधिक है।

यहाँ एक प्रदर्शनकारी कार्यक्रम है।

#include <stdio.h>

int main(void) 
{
    char cnt = -1;
    unsigned char i = cnt - 2;
    
    printf( "cnt = %x\n", ( unsigned int )cnt );
    printf( "i = %x\n", ( unsigned int )i );
    
    printf ( "i < cnt is %s\n", i < cnt ? "true" : "false" );
    
    return 0;
}

प्रोग्राम आउटपुट है

cnt = ffffffff
i = fd
i < cnt is false
1
Vlad from Moscow 2 सितंबर 2021, 13:11