2011-12-23 14 views
17

एक पूर्णांक मान को void* या स्मृति बिंदु से उपरोक्त रूपांतरित करने का क्या अर्थ है? मेरी समझ void* अनिर्दिष्ट लंबाई की स्मृति के एक ब्लॉक के लिए एक पता है।
ऐसा लगता है कि संतरे के साथ सेब की तुलना करना कुछ ऐसा लगता है।int से void * या इसके विपरीत रूपांतरित करने का क्या अर्थ है?

int myval = 5; 
void* ptr = (void*)myval; 
printf("%d",(int)ptr); 

मुझे एहसास हुआ कि मुझे सटीक संदर्भ देना चाहिए था जहां इसका उपयोग किया जाता है।

int main(int argc, char* argv[]) { 
long  thread; /* Use long in case of a 64-bit system */ 
pthread_t* thread_handles; 

/* Get number of threads from command line */ 
if (argc != 2) Usage(argv[0]); 
thread_count = strtol(argv[1], NULL, 10); 
if (thread_count <= 0 || thread_count > MAX_THREADS) Usage(argv[0]); 

thread_handles = malloc (thread_count*sizeof(pthread_t)); 

for (thread = 0; thread < thread_count; thread++) 
    pthread_create(&thread_handles[thread], NULL, Hello, (void*) thread); 

printf("Hello from the main thread\n"); 

for (thread = 0; thread < thread_count; thread++) 
    pthread_join(thread_handles[thread], NULL); 

free(thread_handles); 
return 0; 
} /* main */ 

/*-------------------------------------------------------------------*/ 
void *Hello(void* rank) { 
long my_rank = (long) rank; /* Use long in case of 64-bit system */ 

printf("Hello from thread %ld of %d\n", my_rank, thread_count); 

return NULL; 
} /* Hello */ 

यह कोड पीटर पेचेको की पुस्तक समानांतर प्रोग्रामिंग पर है।

+0

संभावित डुप्लिकेट: http://stackoverflow.com/questions/3568069/is-it-safe-to-cast-an-int-to-void-pointer-and-back-to-int-again –

+1

यह है इससे भी बदतर .. - कम से कम आलू की तुलना में सेब की तुलना करना – alk

उत्तर

17

कास्टिंग int से void * बल्कि अर्थहीन है और ऐसा नहीं किया जाना चाहिए क्योंकि आप एक सूचक को एक पॉइंटर डालने का प्रयास करेंगे। C99 standard का उद्धरण, खंड 6.3.2.3 आइटम 5:

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

आप सकता है डाली int *void * (किसी भी सूचक void * जो आप सभी संकेत के "आधार प्रकार" की तरह के बारे में सोच सकते हैं के लिए परिवर्तनीय है)।

कास्टिंग int को void * पोर्टेबल नहीं है और मंच आप उपयोग के आधार पर पूरी तरह से गलत हो सकता है (उदाहरण के लिए void * शायद 64 बिट्स व्यापक और int केवल 32 बिट हो सकता है)। सी 99 मानक को फिर से उद्धरण, खंड 6.3.2.3 आइटम 6:

कोई भी सूचक प्रकार एक पूर्णांक प्रकार में परिवर्तित किया जा सकता है। पहले निर्दिष्ट को छोड़कर, परिणाम कार्यान्वयन-परिभाषित है। यदि परिणाम पूर्णांक प्रकार में प्रदर्शित नहीं किया जा सकता है, तो व्यवहार अपरिभाषित है। परिणाम किसी भी पूर्णांक प्रकार के मानों की सीमा में नहीं होना चाहिए।

इसे हल करने के लिए, कुछ प्लेटफॉर्म uintptr_t प्रदान करते हैं जो आपको पॉइंटर को उचित चौड़ाई के अंकीय मूल्य के रूप में पेश करने की अनुमति देता है।

3

void* पॉइंटर (या उस मामले के लिए कोई सूचक) और int, मोटे तौर पर बोलते हुए, संख्याएं हैं। वे अलग-अलग बिटसाइट का हो सकते हैं, लेकिन यह संभावना नहीं है कि सूचक int से छोटा है, जिससे ऑपरेशन उलटा हो जाता है। बेशक, यह अवैध है और आपको उस सूचक को कभी भी कम नहीं करना चाहिए जिसमें इंगित करने के लिए कोई वैध स्थान नहीं है।

2

यह सेब और संतरे की तुलना में काफी है। यह कोड एकमात्र तरीका है कि यह कोड काम करता है क्योंकि आप इसे स्पष्ट रूप से आगे और आगे कास्टिंग कर रहे हैं।

सी कंपाइलर सिर्फ इंट से बाइट्स को पॉइंटर और बैक के लिए जगह में कॉपी कर रहा है, जैसे कि आप int में char को कैसे पकड़ सकते हैं।

इससे आपके कारण पर गड़बड़ हो सकती है अगर किसी कारण से 'int' आपके प्लेटफ़ॉर्म पर 'शून्य' से अधिक लंबा हो।

यदि आप वास्तव में पॉइंटर्स और बैक में पूर्णांक से कनवर्ट करने के लिए एक संख्या चाहते हैं, तो intptr_t देखें। वह प्रकार वास्तव में दोनों पूर्णांक और पॉइंटर्स को स्टोर करने के लिए डिज़ाइन किया गया है।

1

पॉइंटर अंकगणितीय के लिए पूर्णांक प्रकार के लिए पॉइंटर डालने में सक्षम होना उपयोगी है। उदाहरण के लिए, offsetof() मैक्रो, जो संरचना के भीतर किसी सदस्य के ऑफ़सेट की गणना करता है, इस तरह के रूपांतरण की आवश्यकता है।

हालांकि, यह सुनिश्चित किया जाना चाहिए कि इसके लिए उपयोग किया जाने वाला आदिम प्रकार एक सूचक को संभालने में सक्षम है: उदाहरण के लिए, 64 लिनक्स के लिए उदाहरण के लिए, जीसीसी का उपयोग करते समय, यह मामला नहीं है: void * आकार 8 है, एक int है आकार 4.

offsetof मैक्रो इस तरह के रूप में परिभाषित किया जाता है:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 

यह लिनक्स कर्नेल का दोगुना लिंक्ड सूची कार्यान्वयन में प्रमुखता से प्रयोग किया जाता है, बहुत बस के रूप में परिभाषित:

struct list_head { struct list_head *prev, *next; } 

यह struct के रूप में, कर्नेल संरचनाओं के भीतर एम्बेडेड है:

struct something { 
    //... 
    struct list_head list; 
    //... 
} 

जब एक सूची घूमना, कोड एन्कोडिंग संरचना करने के लिए एक सूचक हड़पने के लिए की जरूरत है।यह इस (सरलीकृत परिभाषा) के रूप में किया जाता है:

#define container_of(ptr, type, member) \ 
    (type *)((char *)ptr - offsetoff(type, member)) 
#define list_entry(list, type, member) \ 
    container_of(list, type, member) 

और कोड में, आप बहुत बार देखेंगे:

struct something *s; 
list_for_each(listptr, somehead) { 
    s = list_entry(listptr, struct something, list); 
    //... 
} 

जो केवल नहीं स्थूल और सूचक अंकगणित के इस प्रकार के बिना संभव होगा। लेकिन यह टूलचेन पर बहुत निर्भर है।

+0

इसे 'ऑफ़सेट' के साथ क्या करना है। साथ ही, 'ऑफसेटोफ' प्लेटफ़ॉर्म परिभाषित किया गया है, एक कंपाइलर कार्यान्वयन इसे लागू करने के लिए स्वतंत्र है जिस तरह से यह सर्वोत्तम फिट बैठता है। E.g gcc एक आंतरिक द्वारा इसे लागू करता है। –

1

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

+0

यह सच नहीं है कि जानकारी का कोई नुकसान नहीं है। सी 99 मानक कहता है, "किसी भी सूचक प्रकार को एक पूर्णांक प्रकार में परिवर्तित किया जा सकता है। जैसा कि पहले निर्दिष्ट किया गया है, परिणाम कार्यान्वयन-परिभाषित है। यदि परिणाम पूर्णांक प्रकार में प्रदर्शित नहीं किया जा सकता है, तो व्यवहार अपरिभाषित है। परिणाम की आवश्यकता नहीं है किसी भी पूर्णांक प्रकार के मूल्यों की सीमा में। " – bobbymcr

+0

क्षमा करें, मैंने अपना जवाब संपादित किया और उस गलती को सही किया। (मैंने सी 99 के बारे में कुछ और 'विशाल बहुमत' शब्द में 'विशाल' शब्द संपादित किया।) –

+0

"विशाल बहुमत" शायद आज भी झूठा है, और भविष्य में कम और कम संभावना रखेगा। आधुनिक वास्तुकला ज्यादातर 64 पॉइंटर्स और 32 बिट 'int' के साथ हैं। –

3

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

कई मामलों में, विशेष रूप से जब एम्बेडेड नियंत्रकों के लिए विकास करते हैं, तो संकलक विक्रेता स्पष्ट रूप से निर्दिष्ट करेगा कि किसी विशेष पूर्णांक मान को पॉइंटर प्रकार में परिवर्तित करते समय हार्डवेयर पता का उपयोग किया जाएगा। एक रैखिक पता स्थान वाले प्रोसेसर पर, एक पूर्णांक मान 0x12345678 को एक सूचक में कनवर्ट करना आमतौर पर एक सूचक उत्पन्न करता है जो 0x12345678 पते को संदर्भित करता है; हार्डवेयर संदर्भ पुस्तिका इंगित करेगी कि उस स्थान के बारे में कुछ खास था या नहीं। अधिक 'रोचक' पता रिक्त स्थान वाले प्रोसेसर पर, पॉइंटर के रूप में हार्डवेयर पते के अलावा कुछ और उपयोग करना आवश्यक हो सकता है। उदाहरण के लिए, एंटीक आईबीएम पीसी कंप्यूटर पर, डिस्प्ले बफर हार्डवेयर एड्रेस 0xB8000 पर मैप किया गया था, लेकिन अधिकांश कंपाइलर्स में, पता (लघु दूर * 0xB8000000 के रूप में व्यक्त किया जाएगा)।

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