std :: bit_cast with std :: array


14

उनकी हाल ही वार्ता में "आधुनिक सी में टाइप punning ++" तैमूर Doumler कहा कि std::bit_castकरने के लिए थोड़ा और एक डाली नहीं किया जा सकता floatएक में unsigned char[4]क्योंकि सी शैली सरणियों एक समारोह से वापस नहीं किया जा सकता है। हमें या तो std::memcpyC ++ 23 (या बाद में) तक का उपयोग करना चाहिए या करना चाहिए जब कुछ reinterpret_cast<unsigned char*>(&f)[i]अच्छी तरह से परिभाषित हो जाएगा।

सी ++ 20 में, हम एक का उपयोग कर सकते std::arrayके साथ std::bit_cast,

float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);

के बजाय एक सी शैली सरणी बाइट्स पाने के लिए float?

जवाबों:


15

हां, यह सभी प्रमुख संकलकों पर काम करता है, और जहां तक ​​मैं मानक को देखने से कह सकता हूं, यह पोर्टेबल है और काम करने की गारंटी है।

सबसे पहले, std::array<unsigned char, sizeof(float)>एक समग्र ( https://eel.is/c++draft/array#overview-2 ) होने की गारंटी है । इसके बाद से यह sizeof(float)माना जाता है कि यह वास्तव में charअंदर की एक संख्या रखता है (आमतौर पर एक के रूप में char[], हालांकि afaics मानक इस विशेष कार्यान्वयन को अनिवार्य नहीं करता है - लेकिन यह कहता है कि तत्व सन्निहित होने चाहिए) और इसमें कोई अतिरिक्त गैर-स्थैतिक सदस्य नहीं हो सकते।

इसलिए यह तुच्छ रूप से प्रतिलिपि योग्य है, और इसका आकार भी मेल खाता है float

वे दो गुण आपको bit_castउनके बीच की अनुमति देते हैं।


3
ध्यान दें कि struct X { unsigned char elems[5]; };आप जिस नियम का हवाला दे रहे हैं उसे संतुष्ट करता है। यह निश्चित रूप से 4 तत्वों के साथ सूची-आरंभीकृत किया जा सकता है। यह कर सकते हैं भी सूची-प्रारंभ 5 तत्वों के साथ हो सकता है। मुझे नहीं लगता कि किसी भी मानक पुस्तकालय कार्यान्वयनकर्ता को वास्तव में ऐसा करने के लिए लोगों से बहुत नफरत है, लेकिन मुझे लगता है कि यह तकनीकी रूप से अनुरूप है।
बैरी

धन्यवाद! - बैरी, मुझे नहीं लगता कि यह काफी सही है। मानक कहता है: "एन तत्वों के साथ सूची-प्रारंभ किया जा सकता है"। मेरी व्याख्या है कि "अप" का तात्पर्य "इससे अधिक नहीं" है। जिसका मतलब है कि आप ऐसा नहीं कर सकते elems[5]। और उस बिंदु पर मैं यह नहीं देख सकता कि आप एक समग्र के साथ कैसे समाप्त हो सकते हैं sizeof(array<char, sizeof(T)>) != sizeof(T)?
तैमूर डौमलर

मेरा मानना ​​है कि नियम का उद्देश्य ("एक समुच्चय जो सूची-आरंभीकृत किया जा सकता है ...") struct X { unsigned char c1, c2, c3, c4; };या तो अनुमति देने के लिए है या struct X { unsigned char elems[4]; };इसलिए जबकि वर्णों को उस कुल के तत्व होने की आवश्यकता है, इससे उन्हें प्रत्यक्ष कुल तत्व होने की अनुमति मिलती है या एकल उप-कुल के तत्व।
तैमूर डौलर

2
@ तैमूर "से" नहीं "से अधिक नहीं है"। उसी तरह से जब निहितार्थ P -> Qमामले के बारे में कुछ भी नहीं बताता है!P
बैरी

1
भले ही समुच्चय में 4 तत्वों की एक सरणी के अलावा कुछ भी नहीं है, लेकिन कोई गारंटी नहीं है कि arrayस्वयं पैडिंग नहीं होगी। इसके क्रियान्वयन में पैडिंग नहीं हो सकती है (और ऐसा कोई भी कार्यान्वयन जिसे अपचनीय माना जाना चाहिए), लेकिन इसकी कोई गारंटी नहीं है कि arrayस्वयं नहीं होगा।
निकोल बोल्स

6

स्वीकृत उत्तर गलत है क्योंकि यह संरेखण और पैडिंग मुद्दों पर विचार करने में विफल रहता है।

प्रति [सरणी] / 1-3 :

शीर्ष लेख <array>ऑब्जेक्ट के स्थिर-आकार अनुक्रमों को संग्रहीत करने के लिए एक वर्ग टेम्पलेट को परिभाषित करता है। एक सरणी एक सन्निहित कंटेनर है। प्रकार के array<T, N>भंडार Nतत्वों की एक आवृत्ति T, इसलिए size() == Nयह एक अपरिवर्तनीय है।

एक सरणी एक ऐसा समुच्चय है जिसे N ऐसे तत्वों के साथ सूचीबद्ध किया जा सकता है जिनके प्रकार परिवर्तनीय हैं T

एक सरणी कंटेनर की आवश्यकताओं और प्रतिवर्ती कंटेनर ( [container.requirements]) की सभी आवश्यकताओं को पूरा करती है , सिवाय इसके कि एक डिफ़ॉल्ट निर्मित सरणी ऑब्जेक्ट खाली नहीं है और उस स्वैप में निरंतर जटिलता नहीं है। एक सरणी एक अनुक्रम कंटेनर की कुछ आवश्यकताओं को पूरा करती है। वर्णन केवल उन सारणियों के संचालन के लिए दिए गए हैं जो इन तालिकाओं में से किसी एक में वर्णित नहीं हैं और उन कार्यों के लिए जहां अतिरिक्त अर्थ सूचना है।

मानक std::arrayको वास्तव में प्रकार का एक सार्वजनिक डेटा सदस्य होने की आवश्यकता नहीं है T[N], इसलिए सिद्धांत रूप में यह संभव है कि sizeof(To) != sizeof(From)या is_­trivially_­copyable_­v<To>

मुझे आश्चर्य होगा अगर यह अभ्यास में काम नहीं करता है, हालांकि।


2

हाँ।

कागज के अनुसार जो व्यवहार का वर्णन करता है std::bit_cast, और इसके प्रस्तावित कार्यान्वयन जहां तक ​​दोनों प्रकार के आकार समान हैं और तुच्छ रूप से प्रतिलिपि योग्य हैं, कलाकारों को सफल होना चाहिए।

का सरलीकृत कार्यान्वयन std::bit_castकुछ इस तरह होना चाहिए:

template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
    static_assert(sizeof(Dest) == sizeof(Source));
    static_assert(std::is_trivially_copyable<Dest>::value);
    static_assert(std::is_trivially_copyable<Source>::value);

    Dest dest;
    std::memcpy(&dest, &source, sizeof(dest));
    return dest;
}

एक नाव (4 बाइट्स) और की एक सरणी के बाद से unsigned charसाथ size_of(float)संबंध उन सभी का दावा है, अंतर्निहित std::memcpyकिया जाएगा। इसलिए, परिणामी सरणी में प्रत्येक तत्व फ्लोट का एक लगातार बाइट होगा।

इस व्यवहार को साबित करने के लिए, मैंने कंपाइलर एक्सप्लोरर में एक छोटा सा उदाहरण लिखा, जिसे आप यहाँ आज़मा सकते हैं: https://godbolt.org/z/4G21zS । फ्लोट 5.0 को बाइट्स ( Ox40a00000) के एक सरणी के रूप में ठीक से संग्रहीत किया जाता है जो बिग एंडियन में उस फ्लोट संख्या के हेक्साडेसिमल प्रतिनिधित्व से मेल खाती है ।


क्या आप सुनिश्चित हैं कि std::arrayपैडिंग बिट्स आदि की गारंटी नहीं है?
LF

1
दुर्भाग्य से, कुछ कोड काम करता है कि केवल इसमें कोई UB मतलब नहीं है। उदाहरण के लिए, हम auto bits = reinterpret_cast<std::array<unsigned char, sizeof(float)>&>(f)एक ही आउटपुट लिख सकते हैं और प्राप्त कर सकते हैं । क्या यह कुछ साबित करता है?
Evg

विवरणों के आधार पर @LF: std::arrayसंतुष्ट की आवश्यकताओं ContiguiosContainer (सी ++ के बाद से 17)
मैनुअल गिल

1
@ मैन्यूलगिल: std::vectorसमान मानदंडों को भी पूरा करता है और जाहिर तौर पर यहां इसका इस्तेमाल नहीं किया जा सकता है। क्या कुछ आवश्यक है जो std::arrayकक्षा के अंदर (एक क्षेत्र में) तत्वों को पकड़कर रखता है, जो इसे एक सरल पॉइंटर से आंतरिक सरणी में जाने से रोकता है? (सदिश की तरह, जिसका आकार भी होता है, जिसे किसी फ़ील्ड में रखने की आवश्यकता नहीं होती है)
फ़िरदा

@ फ़िरदा std::arrayप्रभावी रूप से तत्वों को संग्रहीत करने के लिए इसे प्रभावी रूप से एकत्र करने की आवश्यकता है, लेकिन मैं लेआउट समस्याओं के बारे में चिंता कर रहा हूं।
LF
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.