क्या कोई कुछ अजीब चेतावनी व्यवहार समझा सकता है।

मुझे लगता है कि यह पूरी तरह से स्याही में परिवर्तित हो रहा है। लेकिन पहली 2 पंक्तियाँ ठीक क्यों हैं? जब ~ ऑपरेटर का उपयोग किया जाता है, तो कंपाइलर चेतावनियां फेंकना शुरू कर देता है। यदि यह इनट्स में परिवर्तित हो रहा है, तो क्या इसे पहली 2 पंक्तियों पर भी चेतावनी नहीं देनी चाहिए?

उबंटू 16.04 जी++5.4

#include <cstdint>
using namespace std;

// g++ -std=c++11 -Wall -Wconversion main.cpp -o main

// warning: conversion to ‘uint8_t {aka unsigned char}’ from ‘int’ may alter its value [-Wconversion]

int main()
{
    uint8_t a = 0x00U;
    uint8_t b = 0x01U;

    a = a | b;  // no warning
    a |= b;     // no warning
    a = ~b;     // warning
    a = a | ~b; // warning
    a |= ~b;    // warning
    return 0;
}
2
rinn2883 12 जुलाई 2018, 13:00
मैं a = a | b; के लिए भी चेतावनी की अपेक्षा करता...
 – 
Jarod42
12 जुलाई 2018, 13:11

3 जवाब

जब एक अंकगणितीय व्यंजक में int से छोटा चर या मान शामिल होता है, तो वह निहित रूप से परिवर्तित एक int में। कुछ प्रकारों के लिए संकलक एक और अंतर्निहित रूपांतरण वापस मूल प्रकार में कर सकता है, लेकिन अन्य में यह डेटा की हानि के बिना संभव नहीं है।

उदाहरण के लिए अपने अहस्ताक्षरित बाइट मान 0x00 को लें। एक int में बदलने पर यह 0x00000000 हो जाता है। बिटवाइज़ पूरक इसे 0xffffffff में बदल देता है, जिसे बिना डेटा खोए वापस अहस्ताक्षरित बाइट में परिवर्तित नहीं किया जा सकता है।

और यह उस तरह के मूल्यों के लिए विशेष रूप से बुरा है, क्योंकि एक int के रूप में मान 0xffffffff -1 के बराबर है (दो का पूरक यह जानने के लिए कि क्यों), जिसे वास्तव में एक अहस्ताक्षरित बाइट में स्पष्ट रूप से परिवर्तित नहीं किया जा सकता है।

इसलिए, और अतिप्रवाह का जोखिम नहीं उठाने के लिए (जब तक कि वह वांछित न हो) मेरा सुझाव है कि आप int (या unsigned int) का उपयोग करके सभी पूर्णांक अंकगणितीय करें। तब तक छोटे प्रकारों में कनवर्ट न करें जब तक आपको इसकी बिल्कुल आवश्यकता न हो।

4
Some programmer dude 12 जुलाई 2018, 13:05
1
जब तक केवल बिना स्थानांतरण वाले बाइनरी ऑपरेटरों का उपयोग किया जाता है, तब तक कोई डेटा हानि या संभावित अतिप्रवाह नहीं होता है। गिराए जाने से पहले बस अतिरिक्त डेटा में हेरफेर किया जाता है। तो उनके मामले में uint8_t का उपयोग करना बिल्कुल ठीक है।
 – 
Benjamin Barrois
12 जुलाई 2018, 13:10

यदि आप कोई चेतावनी नहीं चाहते हैं तो यहां 2 संभावनाएं हैं:

समाधान 1:

int main()
{
    uint8_t a = 0x00U;
    uint8_t b = 0x01U;

    a = a | b;
    a |= b;
    a = static_cast<uint8_t>(~b);
    a = a | static_cast<uint8_t>(~b);
    a |= static_cast<uint8_t>(~b);
    return 0;
}

समाधान 2:

int main()
{
    uint32_t a = 0x00U;
    uint32_t b = 0x01U;

    a = a | b;
    a |= b;
    a = ~b;
    a = a | ~b;
    a |= ~b;
    return 0;
}

आप सोच सकते हैं कि दूसरा कम कुशल है क्योंकि यह बड़ी संख्या का उपयोग करता है, यह वास्तव में गलत है। पहले समाधान में operator ~ की वजह से 32-बिट संख्याओं में निहित रूपांतरणों में कुछ मेमोरी और प्रदर्शन खर्च होता है। दूसरा समाधान वास्तव में अधिक कुशल होना चाहिए। सामान्य तौर पर आपको (कम से कम) uint32_t का उपयोग करना चाहिए और यदि आप 8-बिट मान चाहते हैं तो मास्क का उपयोग करें:

uint32_t value = 0xFFFFFFFF;
uint32_t mask = 0xFFu;

value &= mask; // Now value is 0x000000FF
0
Benjamin Barrois 12 जुलाई 2018, 13:19
1
इस बात की कोई गारंटी नहीं है कि 32-बिट का उपयोग करने से दक्षता बढ़ जाती है। वह संकलक-निर्भर है। सभी कंपाइलर 32-बिट इंटीग्रल प्रकारों के आसपास अनुकूलित नहीं होते हैं।
 – 
Peter
12 जुलाई 2018, 13:27
कंपाइलर नहीं करता है, लेकिन आपका हार्डवेयर आमतौर पर 32-64-बिट पूर्णांक हेरफेर के लिए अधिक अनुकूलित होता है, इसलिए इस बात की प्रबल संभावना है कि सीपीयू पर सब कुछ किसी समय 32/64 बिट में बदल जाता है।
 – 
Benjamin Barrois
12 जुलाई 2018, 13:30
वास्तविक दुनिया का हार्डवेयर भी है जो 32 या 64 बिट पूर्णांकों के लिए अनुकूलित नहीं है। यह एक कारण है (अन्य भी हैं) कि सभी कंपाइलर 32 बिट के साथ काम नहीं करते हैं।
 – 
Peter
12 जुलाई 2018, 13:33
हां, मैंने यह परिकल्पना की थी कि यह एक क्लासिक x86/amd64 प्रणाली थी।
 – 
Benjamin Barrois
12 जुलाई 2018, 13:52

कंपाइलर स्मार्ट है: uint8_t a = 0x00U; uint8_t बी = 0x01U;

a = a | b;  // no warning
a |= b;     // no warning

दो 8 बिट मान दिए गए हैं, | 8 से थोड़ा अधिक सेट नहीं कर सकते हैं। इसलिए वापस 8 बिट्स में कनवर्ट करते समय कोई बिट खो नहीं जाता है।

a|b का परिणाम एक int की परवाह किए बिना है, लेकिन संकलक यह भी जानता है कि यह एक 8 बिट क्लीन इंट है।

~a का परिणाम है नहीं एक 8 बिट क्लीन इंट -- a को एक (शायद 32 बिट) इंट में बदल दिया जाता है, फिर सभी बिट्स उल्टे हो जाते हैं (उच्च बिट्स सेट करना) . तो अगर वापस 8 बिट्स में परिवर्तित किया जाता है तो कुछ सेट हाई ऑर्डर बिट्स खो जाते हैं।

इन सभी मामलों में यह सच है:

a = ~b;     // warning
a = a | ~b; // warning
a |= ~b;    // warning

a=~b के बाद, a==~b सत्य नहीं है। a=a|~b मामले में, यदि हमने परिणाम auto c=a|~b; संग्रहीत किया, तो क्या a=c, a==c बाद में सत्य नहीं होगा। |= मामले में एक समान अवलोकन है जो स्वयं संशोधन द्वारा जटिल है।

0
Yakk - Adam Nevraumont 12 जुलाई 2018, 14:26