Nullptr को uintptr_t में परिवर्तित किया जा सकता है? विभिन्न संकलक असहमत हैं


10

इस कार्यक्रम पर विचार करें:

#include <cstdint>
using my_time_t = uintptr_t;

int main() {
    const my_time_t t = my_time_t(nullptr);
}

यह msvc v19.24 के साथ संकलन करने में विफल रहा:

<source>(5): error C2440: '<function-style-cast>': cannot convert from 'nullptr' to 'my_time_t'
<source>(5): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type
<source>(5): error C2789: 't': an object of const-qualified type must be initialized
<source>(5): note: see declaration of 't'

Compiler returned: 2

लेकिन क्लैग (9.0.1) और जीसीसी (9.2.1) बिना किसी त्रुटि के इस कोड को "खा" लेते हैं।

मुझे MSVC व्यवहार पसंद है, लेकिन क्या यह मानक द्वारा पुष्टि की गई है? दूसरे शब्दों में, यह clang / gcc में बग है या मानक की व्याख्या करना संभव है कि यह gcc / clang से सही व्यवहार है?


2
मैंने इसे फ़ंक्शन-स्टाइल कास्ट से कॉपी इनिशियलाइज़ेशन के रूप में पढ़ा। इसके बाद संकलक द्वारा C ++ कास्ट में से एक के रूप में व्याख्या की जाती है "भले ही इसे संकलित नहीं किया जा सकता है"। हो सकता है कि कलाकारों के बीच एक असंगतता हो कि कैसे कलाकारों की व्याख्या की जाती है
wreckgar23

जहाँ तक मुझे पता है MSVC v19.24 C ++ 11 मोड का समर्थन नहीं करता है। क्या आपके बजाय C ++ 14 या C ++ 17 का मतलब था?
अखरोट

जवाबों:


5

मेरी राय में MSVC मानक-अनुरूप व्यवहार नहीं कर रहा है।

मैं इस उत्तर को C ++ 17 (ड्राफ्ट N4659) पर आधारित कर रहा हूं, लेकिन C ++ 14 और C ++ 11 के समकक्ष शब्द हैं।

my_time_t(nullptr)एक उपसर्ग-अभिव्यक्ति है और क्योंकि my_time_tयह एक प्रकार है और (nullptr)एक कोष्ठक आरंभिक सूची में एक एकल अभिव्यक्ति है, यह एक स्पष्ट कास्ट अभिव्यक्ति के बराबर है। ( [expr.type.conv] / 2 )

स्पष्ट कलाकार विशेष रूप से भी कुछ अलग विशिष्ट C ++ जातियों (एक्सटेंशन के साथ) की कोशिश करता है reinterpret_cast। ( [Expr.cast] /4.4 ) डाले से पहले की कोशिश की reinterpret_castहैं const_castऔर static_cast(एक्सटेंशन के साथ और भी संयोजन में), लेकिन इन कर सकते हैं कलाकारों में से कोई भीstd::nullptr_t एक अभिन्न प्रकार के।

लेकिन reinterpret_cast<my_time_t>(nullptr)सफल होना चाहिए क्योंकि [expr.reinterpret.cast] / 4 का कहना है कि प्रकार का एक मान std::nullptr_tएक अभिन्न प्रकार में परिवर्तित किया जा सकता है जैसे कि reinterpret_cast<my_time_t>((void*)0), जो संभव है क्योंकि my_time_t = std::uintptr_tसभी सूचक मूल्यों का प्रतिनिधित्व करने के लिए एक प्रकार का बड़ा होना चाहिए और इस शर्त के तहत। समान मानक पैराग्राफ void*एक अभिन्न प्रकार के रूपांतरण की अनुमति देता है ।

यह विशेष रूप से अजीब है कि MSVC रूपांतरण की अनुमति देता है यदि कार्यात्मक संकेतन के बजाय कास्ट नोटेशन का उपयोग किया जाता है:

const my_time_t t = (my_time_t)nullptr;

1
हां। ध्यान दें कि static_castविशेष रूप से फँसाने के लिए सी-शैली डाली सीढ़ी का इरादा कुछ मामलों है (उदाहरण के लिए, एक अस्पष्ट आधार के लिए एक सी शैली डाली एक बीमार का गठन है static_castएक के बजाय reinterpret_cast), लेकिन कोई भी यहाँ लागू होता है।
टीसी

my_time_t(nullptr)परिभाषा के अनुसार ही है (my_time_t)nullptr, इसलिए MSVC निश्चित रूप से एक को स्वीकार करने और दूसरे को अस्वीकार करने के लिए गलत है।
रिचर्ड स्मिथ

2

हालाँकि मुझे इस वर्किंग ड्राफ्ट C ++ स्टैण्डर्ड (2014 से) में कोई स्पष्ट उल्लेख नहीं मिल सकता हैstd::nullptr_t अभिन्न प्रकार निषिद्ध है, इस बात का भी कोई उल्लेख नहीं है कि इस तरह के रूपांतरण की अनुमति है!

हालांकि, से रूपांतरण के मामले std::nullptr_tको bool है स्पष्ट रूप से उल्लेख किया है:

४.१२ बूलियन रूपांतरण
अंकगणित, अनकैप्ड एन्यूमरेशन, पॉइंटर या पॉइंटर टू मेंबर टाइप का एक प्रिव्यू टाइप बूल के प्रिव्यू में बदला जा सकता है। शून्य मान, अशक्त सूचक मान या अशक्त सदस्य सूचक मान मिथ्या में परिवर्तित हो जाता है; किसी भी अन्य मान को सत्य में परिवर्तित किया जाता है। प्रत्यक्ष-आरंभीकरण (8.5) के लिए, प्रकार std :: nullptr_t का एक प्रकार टाइप बूल के एक प्रचलन में परिवर्तित किया जा सकता है; परिणामी मूल्य गलत है।

इसके अलावा, इस ड्राफ्ट दस्तावेज में एकमात्र स्थान जहां std::nullptr_tअभिन्न प्रकार से रूपांतरण का उल्लेख किया गया है, "पुन: व्याख्या_कास्ट" अनुभाग में है:

5.2.10 पुनर्व्याख्या कास्ट
...
(4) एक पॉइंटर को स्पष्ट रूप से किसी भी अभिन्न प्रकार में परिवर्तित किया जा सकता है जो इसे धारण करने के लिए पर्याप्त हो। मैपिंग फ़ंक्शन कार्यान्वयन-परिभाषित है। [नोट: यह उन लोगों के लिए अनिश्चित है, जो अंतर्निहित मशीन की एड्रेसिंग संरचना को जानते हैं। - अंतिम नोट] प्रकार std का मान :: nullptr_t को अभिन्न प्रकार में बदला जा सकता है; रूपांतरण का एक ही अर्थ और वैधता है जो अभिन्न प्रकार के (शून्य *) 0 के रूपांतरण के रूप में है। [नोट: किसी भी प्रकार के मान को std :: nullptr_t में बदलने के लिए एक रीइंटरप्रिट_का उपयोग नहीं किया जा सकता है। - अंतिम नोट]

इसलिए, इन दो अवलोकनों से, कोई (IMHO) उचित रूप से यह अनुमान लगा सकता है कि MSVCसंकलक सही है।

संपादित करें : हालांकि, "कार्यात्मक संकेतन कास्ट" का आपका उपयोग वास्तव में विपरीत सुझाव दे सकता है! MSVCसंकलक, में एक सी शैली डाली का उपयोग कर उदाहरण के लिए कोई समस्या नहीं है:

uintptr_t answer = (uintptr_t)(nullptr);

लेकिन (आपके कोड में), यह इस बारे में शिकायत करता है:

uintptr_t answer = uintptr_t(nullptr); // error C2440: '<function-style-cast>': cannot convert from 'nullptr' to 'uintptr_t'

फिर भी, एक ही ड्राफ्ट मानक से:

5.2.3 स्पष्ट प्रकार रूपांतरण (कार्यात्मक संकेतन)
(1) एक साधारण-प्रकार-विनिर्देशक (7.1.6.2) या टाइप-नेम-स्पेसिफायर (14.6) के बाद एक कोष्ठक अभिव्यक्ति-सूची द्वारा निर्दिष्ट प्रकार के मूल्य का निर्माण होता है जिसे अभिव्यक्ति सूची दी गई है। यदि अभिव्यक्ति सूची एक एकल अभिव्यक्ति है, तो टाइप रूपांतरण अभिव्यक्ति समतुल्य कास्ट एक्सप्रेशन (5.4) में समतुल्य (परिभाषितता में, और यदि अर्थ में परिभाषित किया गया है) है। ...

"संबंधित कास्ट एक्सप्रेशन (5.4)" सी-स्टाइल कास्ट को संदर्भित कर सकता है।


0

सभी मानक अनुरूप हैं (C ++ के लिए रेफरी। ड्राफ्ट n4659)।

nullptr के रूप में परिभाषित किया गया है:

पॉइंटर शाब्दिक कीवर्ड nullptr है। यह प्रकार std :: nullptr_t का एक प्रकार है। [नोट: ..., इस प्रकार का एक प्रहार एक अशक्त सूचक स्थिरांक है और इसे एक अशक्त सूचक मान या अशक्त सदस्य सूचक मान में परिवर्तित किया जा सकता है।]

यहां तक ​​कि अगर नोट गैर-मानक हैं, तो यह स्पष्ट करता है कि मानक के लिए, nullptrएक अशक्त सूचक मान में परिवर्तित होने की उम्मीद है ।

हम बाद में [conv.ptr] में पाते हैं:

अशक्त सूचक स्थिरांक शून्य या प्रकार std :: nullptr_t के मूल्य के साथ पूर्णांक शाब्दिक है। एक अशक्त सूचक स्थिरांक को एक सूचक प्रकार में परिवर्तित किया जा सकता है; .... अभिन्न प्रकार के एक अशक्त सूचक स्थिरांक को एक प्रकार के std :: nullptr_t के रूप में परिवर्तित किया जा सकता है।

यहाँ फिर से मानक की आवश्यकता है कि 0एक std::nullptr_tऔर करने के लिए परिवर्तित किया जा सकता हैnullptr किसी भी सूचक प्रकार में बदला जा सकता।

मेरा पढ़ना यह है कि मानक की कोई आवश्यकता नहीं है कि क्या nullptrइसे सीधे अभिन्न प्रकार में परिवर्तित किया जा सकता है या नहीं। उस पल से:

  • MSVC एक सख्त रीडिंग है और रूपांतरण को मना करता है
  • क्लैंग और जीसीसी व्यवहार करता है जैसे कि एक मध्यस्थ void *रूपांतरण शामिल था।

1
मुझे लगता है कि यह गलत है। कुछ शून्य सूचक स्थिरांक मान शून्य के साथ पूर्णांक शाब्दिक हैं, लेकिन nullptrऐसा नहीं है क्योंकि इसमें गैर-अभिन्न प्रकार है std::nullptr_t। 0 को एक std::nullptr_tमान में बदला जा सकता है , लेकिन शाब्दिक के लिए नहीं nullptr। यह सभी जानबूझकर है, std::nullptr_tअनपेक्षित रूपांतरणों को रोकने के लिए अधिक प्रतिबंधित प्रकार है।
मर्सल्ट्स

@ दलाल: मुझे लगता है कि आप सही हैं। मैं इसे फिर से तैयार करना चाहता था और यह गलत था। मैंने अपनी टिप्पणी के साथ अपनी पोस्ट को संपादित किया है। आपके सहयोग के लिए धन्यवाद।
सर्ग बलेस्टा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.