C ++ enums पर हस्ताक्षर किए हैं या अहस्ताक्षरित हैं?


107

C ++ enums पर हस्ताक्षर किए हैं या अहस्ताक्षरित हैं? और एक्सटेंशन द्वारा किसी इनपुट को यह सत्यापित करके सुरक्षित करना सुरक्षित है कि यह <= आपका अधिकतम मूल्य है, और बाहर छोड़ दें> = आपका न्यूनतम मूल्य (मान लें कि आपने 0 से शुरू किया था और 1 द्वारा बढ़ाया गया था)?


जब हम एक संदर्भ में एक एनुम प्रकार का उपयोग कर रहे हैं जिसके लिए इसके संकेत की आवश्यकता होती है, तो हम वास्तव में एनम को एक अभिन्न प्रकार से परिवर्तित करने के बारे में बात कर रहे हैं। C ++ 03 मानक कहता है कि यह इंटीग्रल प्रमोशन द्वारा किया गया है, जो कि एनम के अंतर्निहित प्रकार से संबंधित कुछ भी नहीं है। इसलिए, मुझे समझ में नहीं आता है कि क्यों हर उत्तर में अंतर्निहित प्रकार को मानक द्वारा परिभाषित नहीं किया गया है? मैंने यहाँ अपेक्षित
व्यवहारों का

जवाबों:


60

आपको किसी विशिष्ट प्रतिनिधित्व पर भरोसा नहीं करना चाहिए। निम्नलिखित लिंक पढ़ें । इसके अलावा, मानक का कहना है कि यह कार्यान्वयन-परिभाषित है, जो एक अभिन्न प्रकार के लिए एक अभिन्न प्रकार के रूप में उपयोग किया जाता है, सिवाय इसके कि यह इंट से बड़ा नहीं होगा, जब तक कि कुछ मूल्य इंट या अहस्ताक्षरित इंट में फिट नहीं हो सकते।

संक्षेप में: आप किसी ऐसे एनम पर भरोसा नहीं कर सकते हैं जिस पर हस्ताक्षर किए गए हैं या अहस्ताक्षरित हैं।


28
माइकल बूर का जवाब (जो मानक को उद्धृत करता है) का तात्पर्य है कि आप इस पर हस्ताक्षर किए जाने पर भरोसा कर सकते हैं यदि आप "गणना में परिभाषित सभी प्रगणक मानों का प्रतिनिधित्व करने में सक्षम" होने के कारण एनुम मान को नकारात्मक के रूप में परिभाषित करते हैं।
सैमुअल हरमर

101

स्रोत पर चलते हैं। यहाँ सी ++ 03 मानक (आईएसओ / आईईसी 14882: 2003) दस्तावेज़ 7.2-5 (गणना घोषणा) में कहा गया है:

एन्यूमरेशन का अंतर्निहित प्रकार एक अभिन्न प्रकार है जो एन्यूमरेशन में परिभाषित सभी एन्यूमरेटर मानों का प्रतिनिधित्व कर सकता है। यह कार्यान्वयन-परिभाषित है जो एक अभिन्न प्रकार के लिए अंतर्निहित प्रकार के रूप में अभिन्न प्रकार का उपयोग किया जाता है, सिवाय इसके कि अंतर्निहित प्रकार int से बड़ा नहीं होगा जब तक कि एक एन्यूमरेटर का मान किसी int या अहस्ताक्षरित int में फिट नहीं हो सकता।

संक्षेप में, आपका संकलक चुनने के लिए जाता है (जाहिर है, यदि आपके पास अपने कुछ ज्ञान मूल्यों के लिए नकारात्मक संख्याएं हैं, तो यह हस्ताक्षरित होगा)।


हम संकलक अनुमानों से कैसे बच सकते हैं और यह बता सकते हैं कि जब सभी गणना मूल्य छोटे, धनात्मक पूर्णांक होते हैं, तो एक अंतर्निहित अहस्ताक्षरित प्रकार का उपयोग करते हैं। (हम एक UBsan ढूंढ रहे हैं क्योंकि कंपाइलर एक इंट, और int का पीड़ित अतिप्रवाह उठा रहा है। मूल्य अहस्ताक्षरित और सकारात्मक है, और हमारा उपयोग अहस्ताक्षरित रैप पर निर्भर करता है कि वह एक डिक्रीमेंट या "नकारात्मक स्ट्राइड" प्रदान करे।)
jww

@jww - यह इस बात पर निर्भर करेगा कि आप वास्तव में किस कंपाइलर का उपयोग कर रहे हैं, मुझे लगता है। चूंकि मानक अंतर्निहित प्रकार को निर्धारित नहीं करता है, और इसे कार्यान्वयन के लिए छोड़ देता है, फिर अपने टूल के दस्तावेज़ को देखने और यह देखने की आवश्यकता है कि क्या यह विकल्प संभव है। यदि आप अपने कोड में एक निश्चित व्यवहार की गारंटी देना चाहते हैं, तो अभिव्यक्ति में आपके द्वारा उपयोग किए जाने वाले एनम सदस्य को क्यों नहीं डालें?
ysap

22

आपको उन पर निर्भर या हस्ताक्षरित नहीं होना चाहिए। यदि आप उन्हें स्पष्ट रूप से हस्ताक्षरित या अहस्ताक्षरित करना चाहते हैं, तो आप निम्नलिखित का उपयोग कर सकते हैं:

enum X : signed int { ... };    // signed enum
enum Y : unsigned int { ... };  // unsigned enum

11
केवल भविष्य में C ++ 0x मानक।
dalle

3
@dalle Microsoft संकलक भी टाइप किए गए enums msdn.microsoft.com/en-us/library/2dzy4k6e(v=vs.80).aspx
teodozjan

15

आपको इस पर भरोसा नहीं करना चाहिए कि या तो हस्ताक्षरित या अहस्ताक्षरित है। मानक के अनुसार यह कार्यान्वयन-परिभाषित है जो एक अभिन्न के लिए अंतर्निहित प्रकार के रूप में अभिन्न प्रकार का उपयोग किया जाता है। अधिकांश कार्यान्वयनों में, हालांकि, यह एक हस्ताक्षरित पूर्णांक है।

C ++ 0x में दृढ़ता से टाइप किए गए एन्यूमरेशन जोड़े जाएंगे जो आपको एनम के प्रकार को निर्दिष्ट करने की अनुमति देगा जैसे:

enum X : signed int { ... };    // signed enum
enum Y : unsigned int { ... };  // unsigned enum

अब भी, हालांकि, कुछ सरल सत्यापन को वैरिएबल या पैरामीटर प्रकार के रूप में एनम का उपयोग करके प्राप्त किया जा सकता है:

enum Fruit { Apple, Banana };

enum Fruit fruitVariable = Banana;  // Okay, Banana is a member of the Fruit enum
fruitVariable = 1;  // Error, 1 is not a member of enum Fruit
                    // even though it has the same value as banana.

मुझे लगता है कि आपका दूसरा उदाहरण थोड़ा उलझन में है :)
मिरल

5

कंपाइलर तय कर सकता है कि एनमों पर हस्ताक्षर किए गए हैं या अहस्ताक्षरित हैं।

एनम को मान्य करने का एक अन्य तरीका यह है कि एनुम को एक चर प्रकार के रूप में उपयोग किया जाए। उदाहरण के लिए:

enum Fruit
{
    Apple = 0,
    Banana,
    Pineapple,
    Orange,
    Kumquat
};

enum Fruit fruitVariable = Banana;  // Okay, Banana is a member of the Fruit enum
fruitVariable = 1;  // Error, 1 is not a member of enum Fruit even though it has the same value as banana.

5

यहां तक ​​कि कुछ पुराने जवाबों में 44 उत्थान मिले, मैं उन सभी से असहमत हूं। संक्षेप में, मुझे नहीं लगता कि हमें underlying typeएनम के बारे में परवाह करनी चाहिए ।

सबसे पहले, C ++ 03 Enum टाइप का अपना एक अलग प्रकार है जिसमें साइन की कोई अवधारणा नहीं है। चूंकि सी ++ 03 मानक सेdcl.enum

7.2 Enumeration declarations 
5 Each enumeration defines a type that is different from all other types....

इसलिए जब हम एक एनम प्रकार के संकेत के बारे में बात कर रहे हैं, तो कहिए कि <ऑपरेटर का उपयोग करते हुए 2 एनम ऑपरेंड्स की तुलना करते हुए , हम वास्तव में एनुम प्रकार को कुछ अभिन्न प्रकार में परिवर्तित करने के बारे में बात कर रहे हैं। यह इस अभिन्न प्रकार का संकेत है जो मायने रखता है । और जब एनम को अभिन्न प्रकार में परिवर्तित करते हैं, तो यह कथन लागू होता है:

9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5).

और, जाहिर है, इनम के अंतर्निहित प्रकार का इंटीग्रल प्रमोशन से कोई लेना-देना नहीं है। चूंकि मानक इस तरह इंटीग्रल प्रमोशन को परिभाषित करता है:

4.5 Integral promotions conv.prom
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long.

तो, क्या एक एनुम प्रकार बनता है signed intया unsigned intइस पर निर्भर करता है कि क्या signed intपरिभाषित एन्यूमरेटर्स के सभी मूल्य शामिल हो सकते हैं, एनम के अंतर्निहित प्रकार नहीं।

मेरे संबंधित प्रश्न देखें इंटीग्रल टाइप में बदलने के बाद C ++ Enum टाइप का गलत नाम


यह तब मायने रखता है जब आप इसके साथ संकलित कर रहे हैं -Wsign-conversion। हम इसका उपयोग अपने कोड में अनपेक्षित गलतियों को पकड़ने में मदद करने के लिए करते हैं। लेकिन +1 मानक का हवाला देते हुए, और उनका कहना है एक enum कोई प्रकार (है कि के लिए signedबनाम unsigned) इसके साथ जुड़े।
jww

4

भविष्य में, C ++ 0x के साथ, दृढ़ता से टाइप किए गए एन्यूमरेशन्स उपलब्ध होंगे और कई फायदे होंगे (जैसे टाइप-सेफ्टी, स्पष्ट अंतर्निहित प्रकार, या स्पष्ट स्कूपिंग)। इससे आप टाइप के संकेत के बारे में बेहतर आश्वस्त हो सकते हैं।


4

हस्ताक्षरित / अहस्ताक्षरित के बारे में अन्य लोगों ने पहले से ही क्या कहा है, इसके अलावा यहाँ मानक मानक की गणना के प्रकार के बारे में क्या कहते हैं:

7.2 (6): "एक गणना के लिए जहां ई (न्यूनतम) सबसे छोटा गणनाकर्ता है और ई (अधिकतम) सबसे बड़ा है, गणना के मान बी (अधिकतम) से बी (अधिकतम) में अंतर्निहित प्रकार के मान हैं ), जहां b (न्यूनतम) और b (अधिकतम) क्रमशः, सबसे छोटे बिटफील्ड के सबसे छोटे और सबसे बड़े मूल्य हैं जो e (min) और e (अधिकतम) को संग्रहीत कर सकते हैं। यह एक गणना को परिभाषित करना संभव है जिसमें मान परिभाषित नहीं हैं। इसके किसी भी enumerators द्वारा। "

उदाहरण के लिए:

enum { A = 1, B = 4};

एक एन्यूमरेटेड प्रकार को परिभाषित करता है, जहां ई (मिनट) 1 और ई (अधिकतम) है 4. यदि अंतर्निहित प्रकार पर हस्ताक्षर किए गए हैं, तो सबसे छोटी आवश्यक बिटफील्ड में 4 बिट्स हैं, और यदि आपके कार्यान्वयन में इनट्स दो के पूरक हैं तो मान्य रेंज enum is -8 to 7. यदि अंतर्निहित प्रकार अहस्ताक्षरित है, तो इसमें 3 बिट्स हैं और सीमा 0 से 7 है। अपने कंपाइलर प्रलेखन की जांच करें यदि आप देखभाल करते हैं (उदाहरण के लिए यदि आप एन्यूमरेटर्स के अलावा अभिन्न मानों को कास्ट करना चाहते हैं तो प्रगणित प्रकार, तो आपको यह जानना होगा कि मान गणना की सीमा में है या नहीं - यदि नहीं तो परिणामी गणना मान अनिर्दिष्ट है)।

क्या वे मान आपके फ़ंक्शन के लिए मान्य इनपुट हैं, चाहे वे एनुमरेटेड प्रकार के मान्य मान हैं, से कोई भिन्न समस्या हो सकती है। आपका चेकिंग कोड शायद बाद के बजाय पूर्व के बारे में चिंतित है, और इसलिए इस उदाहरण में कम से कम>> ए और <= बी चेक करना चाहिए।


0

std::is_signed<std::underlying_typeडिफ़ॉल्ट रूप से + स्कोप किए गए एनम के साथ इसे जांचेंint

https://en.cppreference.com/w/cpp/language/enum का तात्पर्य:

main.cpp

#include <cassert>
#include <iostream>
#include <type_traits>

enum Unscoped {};
enum class ScopedDefault {};
enum class ScopedExplicit : long {};

int main() {
    // Implementation defined, let's find out.
    std::cout << std::is_signed<std::underlying_type<Unscoped>>() << std::endl;

    // Guaranteed. Scoped defaults to int.
    assert((std::is_same<std::underlying_type<ScopedDefault>::type, int>()));

    // Guaranteed. We set it ourselves.
    assert((std::is_same<std::underlying_type<ScopedExplicit>::type, long>()));
}

गिटहब ऊपर

संकलित करें और चलाएं:

g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main

आउटपुट:

0

उबंटू 16.04, जीसीसी 6.4.0 पर परीक्षण किया गया।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.