2011-09-26 15 views
5

के साथ साइन एक्सटेंशन हमें कुछ अजीब मूल्यों का उत्पादन हुआ, एक छोटा परीक्षण मामला नीचे है। यह प्रिंट करता है "एफएफएफएफएफएफएफएफएफ 9ए 64 सी 2 ए"। ऐसा लगता है कि हस्ताक्षर किए गए लंबे समय तक लंबे समय तक साइन किया गया है। लेकिन क्यों? नीचे दिए गए सभी प्रकार हस्ताक्षरित हैं, तो साइन एक्सटेंशन क्या कर रहा है? अपेक्षित आउटपुट "F9A64C2A" होगा।हस्ताक्षरित लंबे लंबे

#include <stdio.h> 

int main(int argc,char *argv[]) 
{ 
    unsigned char a[] = {42,76,166,249}; 

    unsigned long long ts; 
    ts = a[0] | a[1] << 8U | a[2] << 16U | a[3] << 24U; 

    printf("%llX\n",ts); 


    return 0; 

} 

उत्तर

5

अभिव्यक्ति a[3] << 24U में, a[1] टाइप unsigned char है। अब, "पूर्णांक पदोन्नति" int में बदल देता है क्योंकि:

निम्नलिखित एक अभिव्यक्ति में इस्तेमाल किया जा सकता जहाँ भी एक int या unsigned int इस्तेमाल किया जा सकता है:

[...]

यदि int मूल प्रकार के सभी मानों का प्रतिनिधित्व कर सकता है, तो मान को int में परिवर्तित कर दिया गया है; अन्यथा, इसे unsigned int में परिवर्तित किया गया है।

((draft) ISO/IEC 9899:1999, 6.3.1.1 2)

कृपया ध्यान दें यह भी कहा कि पारी ऑपरेटरों (सबसे अन्य ऑपरेटरों के अलावा अन्य) नहीं एक आम प्रकार के लिए दोनों ऑपरेंड परिवर्तित "सामान्य गणित रूपांतरण" करते हैं । लेकिन

परिणाम का प्रकार प्रचारित बाएं ऑपरेंड का है।

(6.5.7 3)

एक 32 बिट मंच पर, 249 << 24 = 4177526784 व्याख्या के रूप में एक int इसके संकेत बिट सेट है।

बस

ts = a[0] | a[1] << 8 | a[2] << 16 | (unsigned)a[3] << 24; 

फिक्स मुद्दे पर बदल रहा है (स्थिरांक के लिए प्रत्यय U प्रभावित नहीं होती)।

+0

मामूली सुधार: 'एक [1] 'प्रकार' हस्ताक्षरित char' है। –

+0

@ user964970: फिर से पढ़ें। 'X << y' के प्रकार के पास 'y' के प्रकार से कोई लेना देना नहीं है। –

+0

@ डायट्रिच एपीपी: धन्यवाद। –

1
 
ts = ((unsigned long long)a[0]) | 
    ((unsigned long long)a[1] << 8U) | 
    ((unsigned long long)a[2] << 16U) | 
    ((unsigned long long)a[3] << 24U); 

कास्टिंग डिफ़ॉल्ट पूर्णांक प्रकार के मध्यवर्ती परिणाम परिवर्तित करने से रोकता है।

+1

लेकिन * क्यों * एक इंटरमीडिएट int परिणाम है, जब सभी प्रकार शामिल हैं हस्ताक्षरित प्रकार हैं? अपराधी केवल पहला 'एक [0]' लगता है, जिसे बदलकर '(हस्ताक्षरित) एक [0]' सब ठीक है। पर क्यों। – user964970

1

कुछ स्थानांतरित हुए [i], जब स्वचालित रूप से unsigned char से int में परिवर्तित हो जाते हैं, तो साइन-विस्तारित मान उत्पन्न करते हैं।

यह धारा 6.3.1 अंकगणितीय संचालन, उपधारा 6.3.1.1 सी ड्राफ्ट मानक एन 1570 के बूलियन, वर्ण, और पूर्णांक, जो भाग में पढ़ता है, के अनुसार है, "2. अभिव्यक्ति में निम्नलिखित का उपयोग किया जा सकता है जहां भी एक int या unsigned int का उपयोग किया जा सकता है: ... - एक पूर्णांक प्रकार (int या unsigned int के अलावा) के साथ एक ऑब्जेक्ट या अभिव्यक्ति जिसका पूर्णांक रूपांतरण रैंक int और unsigned int के रैंक से कम या बराबर है। .. यदि कोई int मूल प्रकार के सभी मानों का प्रतिनिधित्व कर सकता है ..., मान को int में परिवर्तित किया जाता है, अन्यथा, इसे एक हस्ताक्षरित int में परिवर्तित कर दिया जाता है। इन्हें पूर्णांक प्रचार कहा जाता है। ... 3. पूर्णांक प्रचार संकेत सहित मूल्य को संरक्षित करें। "

देखें जैसे www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf

आप कोड निम्नलिखित है, जो ठीक काम करता है की तरह इस्तेमाल कर सकते हैं:

 int i; 
     for (i=3, ts=0; i>=0; --i) ts = (ts<<8) | a[i]; 
+0

सभी एक [i] जिन्हें स्थानांतरित किया गया है, उदाहरण कोड में, स्थिर पर यू उपसर्ग के कारण हस्ताक्षरित के रूप में दाएं हाथ की ओर है। (उदा। << 8 यू), जिसका अर्थ है उदा। अभिव्यक्ति एक नियम [1] << 8U पहले से ही हस्ताक्षरित प्रकार होना चाहिए, उन नियमों के अनुसार। – user964970

+0

@ user964970: अपराधी 'एक [0]' नहीं है। हालांकि, '[0] 'से' हस्ताक्षरित 'कास्टिंग बिटवाई के परिणाम को बल देता है या' हस्ताक्षरित 'होने के लिए मजबूर करता है, जो' [3] << 24' में दिखाई देने वाले साइन एक्सटेंशन को छोटा करता है, जो असली अपराधी है। –

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