C + (या: C99 में C99% z के निकटतम समतुल्य) के लिए printf size_t को क्लीन कोड दें)


96

मेरे पास कुछ C ++ कोड है जो एक प्रिंट करता है size_t:

size_t a;
printf("%lu", a);

मैं 32- और 64-बिट आर्किटेक्चर दोनों पर चेतावनी के बिना संकलन करना चाहता हूं।

यदि यह C99 थे, तो मैं उपयोग कर सकता था printf("%z", a);। लेकिन AFAICT %zकिसी भी मानक C ++ बोली में मौजूद नहीं है। इसलिए इसके बजाय, मुझे करना होगा

printf("%lu", (unsigned long) a);

जो वास्तव में बदसूरत है।

यदि size_tभाषा में निर्मित मुद्रण के लिए कोई सुविधा नहीं है , तो मुझे आश्चर्य होता है कि क्या प्रिंटफ के रैपर या सोमेसच को लिखना संभव है, जो कि size_tएस पर उपयुक्त कलाकारों को सम्मिलित करेगा ताकि अच्छे लोगों को बनाए रखते हुए संयमी संकलक चेतावनी को समाप्त किया जा सके।

कोई विचार?


संपादित करें यह स्पष्ट करने के लिए कि मैं प्रिंटफ का उपयोग क्यों कर रहा हूं: मेरे पास अपेक्षाकृत बड़ा कोड आधार है जिसे मैं साफ कर रहा हूं। यह "एक चेतावनी लिखें, एक फ़ाइल में लॉग इन करें, और संभवतः एक त्रुटि के साथ कोड से बाहर निकलें" जैसी चीजों को करने के लिए प्रिंटफ़ रैपर का उपयोग करता है। मैं एक पर्याप्त आवरण के साथ ऐसा करने के लिए पर्याप्त C ++ - foo को सक्षम करने में सक्षम हो सकता हूं, लेकिन मैं केवल कुछ संकलक चेतावनियों से छुटकारा पाने के लिए कार्यक्रम में हर चेतावनी () कॉल को नहीं बदलूंगा।


4
आप प्रिंटफ का उपयोग क्यों कर रहे हैं, यह सवाल होना चाहिए।
एड एस।

क्या आपका कंपाइलर आपके लिए प्रिंटफ स्ट्रिंग और टाइप चेक की जांच करता है?
पॉड

मेरा कंपाइलर वास्तव में प्रिंटफ़ प्रारूप स्ट्रिंग का निरीक्षण करता है और इसे मेरे लिए टाइप करता है। मैं इस सुविधा को चालू रखना चाहूंगा।
जस्टिन एल।

2
% zu, z एक चौड़ाई निर्दिष्ट करने वाला है जो विशिष्ट प्रकार नहीं है। यह सी प्रिंटफ के लिए काम करता है जिसे आप सी ++ से मूल उपयोग कर सकते हैं। ); मैं नीचे इस पर टिप्पणी की है, इसलिए इसके लिए वोट
विल

यदि आप विज़ुअल स्टूडियो का उपयोग कर रहे हैं, तो क्या आप उपयोग नहीं कर सकते "%l"? हमेशा सही आकार नहीं होगा? या पोर्टेबिलिटी मायने रखती है?
मूविंग डक

जवाबों:


61

अधिकांश कंपाइलर्स के पास अपनी तर्क size_tऔर ptrdiff_tदलीलें होती हैं, उदाहरण के लिए Visual C ++ क्रमशः% Iu और% Id का उपयोग करता है, मुझे लगता है कि gcc आपको% zu और% zd का उपयोग करने की अनुमति देगा।

आप एक मैक्रो बना सकते हैं:

#if defined(_MSC_VER) || defined(__MINGW32__) //__MINGW32__ should goes before __GNUC__
  #define JL_SIZE_T_SPECIFIER    "%Iu"
  #define JL_SSIZE_T_SPECIFIER   "%Id"
  #define JL_PTRDIFF_T_SPECIFIER "%Id"
#elif defined(__GNUC__)
  #define JL_SIZE_T_SPECIFIER    "%zu"
  #define JL_SSIZE_T_SPECIFIER   "%zd"
  #define JL_PTRDIFF_T_SPECIFIER "%zd"
#else
  // TODO figure out which to use.
  #if NUMBITS == 32
    #define JL_SIZE_T_SPECIFIER    something_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_signed
    #define JL_PTRDIFF_T_SPECIFIER something_signed
  #else
    #define JL_SIZE_T_SPECIFIER    something_bigger_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_bigger_signed
    #define JL_PTRDIFF_T_SPECIFIER something-bigger_signed
  #endif
#endif

उपयोग:

size_t a;
printf(JL_SIZE_T_SPECIFIER, a);
printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);

5
यह इतना आसान नहीं है। चाहे %zसमर्थित है या नहीं क्रम, नहीं संकलक पर निर्भर करता है। __GNUC__इसलिए का उपयोग करना थोड़ा मुश्किल है, यदि आप msvcrt के साथ GCC / mingw को मिलाते हैं (और mingw के संवर्धित प्रिंट का उपयोग किए बिना)।
जोर्जेंसन 6

68

printfफॉर्मेट स्पेसिफायर %zuसी ++ सिस्टम पर कार्य करेंगे; इसे और अधिक जटिल बनाने की कोई आवश्यकता नहीं है।


9
@ क्रिसमर्ले एक त्वरित परीक्षण मुझे दिखाता है कि यह मिनगव में काम नहीं करता है। इसके अलावा एमएस साइट इसे सूचीबद्ध नहीं करती है ( msdn.microsoft.com/en-us/library/tcxf1dw6%28v=vs.100%29.aspx )। मुझे लगता है कि जवाब नहीं है।
17

17

सी ++ 11

C ++ 11 आयात C99 इसलिए std::printfC99 %zuप्रारूप विनिर्देशक का समर्थन करना चाहिए ।

सी ++ 98

अधिकांश प्लेटफ़ॉर्म पर, size_tऔर uintptr_tसमतुल्य हैं, जिस स्थिति में आप PRIuPTRपरिभाषित मैक्रो का उपयोग कर सकते हैं <cinttypes>:

size_t a = 42;
printf("If the answer is %" PRIuPTR " then what is the question?\n", a);

यदि आप वास्तव में सुरक्षित रहना चाहते हैं, तो कास्ट करें uintmax_tऔर उपयोग करें PRIuMAX:

printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));

16

विंडोज़ और प्रिंट के विजुअल स्टूडियो कार्यान्वयन पर

 %Iu

मेरे लिये कार्य करता है। msdn देखें


धन्यवाद। में VS 2008भी काम करता है। यह भी ध्यान रखें कि एक का उपयोग कर सकते हैं %Id, %Ixऔर %IXभी।
c00000fd

11

जब से आप C ++ का उपयोग कर रहे हैं, तो IOStreams का उपयोग क्यों नहीं करते? यह चेतावनी के बिना संकलित करना चाहिए और सही प्रकार-जागरूक चीज़ करना चाहिए, जब तक कि आप एक ब्रेन-डेड C ++ कार्यान्वयन का उपयोग नहीं कर रहे हैं जो एक के operator <<लिए परिभाषित नहीं करता है size_t

जब वास्तविक आउटपुट के साथ काम करना होता है printf(), तब भी आप टाइप-सुरक्षित व्यवहार प्राप्त करने के लिए इसे IOStreams के साथ जोड़ सकते हैं:

size_t foo = bar;
ostringstream os;
os << foo;
printf("%s", os.str().c_str());

यह सुपर-कुशल नहीं है, लेकिन आपका मामला ऊपर फ़ाइल I / O से संबंधित है, इसलिए यह आपकी अड़चन है, न कि यह स्ट्रिंग स्वरूपण कोड।


मुझे पता है कि Google अपने कोड में cout के उपयोग को मना करता है। शायद जस्टिन एल इस तरह के प्रतिबंध के तहत काम कर रहे हैं।

मेरे मामले में (ऊपर संपादित देखें), कटऑफ के संदर्भ में चेतावनी () फ़ंक्शन को लागू करने और लागू करने के लिए एक दिलचस्प विचार हो सकता है। लेकिन इसमें मैन्युअल रूप से पार्सिंग प्रारूप शामिल होगा, जो कि ... मुश्किल है। :)
जस्टिन एल।

आपका नवीनतम संपादन वास्तव में मेरे विचार से मेरे लिए काम करने के विपरीत है। मैं उन सभी कोड को फिर से लिखना नहीं चाहता, जो एक प्रिंटफ़ रैपर को आमंत्रित करते हैं, लेकिन मैं cout का उपयोग करने के लिए printf आवरण के कार्यान्वयन को फिर से लिखना नहीं चाहूंगा। लेकिन मुझे नहीं लगता कि ऐसा होने वाला है। :)
जस्टिन एल।

std::stringstreamIO धाराओं के बजाय का उपयोग करें ।
थॉमस एडिंग

1
धाराओं में अजीब संकेतन है। तुलना: printf("x=%i, y=%i;\n", x, y);बनाम cout << "x=" << x << ", y=" << y << ";" << std::endl;
Wonder.mice

7

यहाँ एक संभव समाधान है, लेकिन यह एक बहुत एक नहीं है ..

template< class T >
struct GetPrintfID
{
  static const char* id;
};

template< class T >
const char* GetPrintfID< T >::id = "%u";


template<>
struct GetPrintfID< unsigned long long > //or whatever the 64bit unsigned is called..
{
  static const char* id;
};

const char* GetPrintfID< unsigned long long >::id = "%lu";

//should be repeated for any type size_t can ever have


printf( GetPrintfID< size_t >::id, sizeof( x ) );

2
खैर ... जो सुरक्षा के अपने लक्ष्य को प्राप्त करता है और कोई चेतावनी नहीं। लेकिन ... Yeesh। अगर मुझे जो करना है, मैं चेतावनी देता हूँ। :)
जस्टिन एल।

1
सुंदर नहीं?! स्वाद पर निर्भर करता है। यह uintptr_t और समान जैसे जानवरों के साथ प्रिंटफ के पूरी तरह से पोर्टेबल उपयोग की अनुमति देता है। महान!
स्लाव

@ user877329 आप उस प्रारूप स्ट्रिंग को एक std :: string के रूप में बना सकते हैं और उसके बाद GetPrintfID <size_t> :: id को उस स्थान पर संलग्न करें जहाँ आपको इसकी आवश्यकता है
stijn

कोई संकलन समय संयोजन availible: दूसरे शब्दों में @stijn
user877329

@ user877329 नहीं (जब तक मैक्रोज़ का उपयोग नहीं कर रहा हूं, या मैं कुछ याद कर रहा हूं)। लेकिन यह एक कठिन आवश्यकता क्यों होगी?
टिजिन

4

Fmt पुस्तकालय की एक तेजी से पोर्टेबल (और सुरक्षित) कार्यान्वयन प्रदान करता है printfसहितz के लिए संशोधक size_t:

#include "fmt/printf.h"

size_t a = 42;

int main() {
  fmt::printf("%zu", a);
}

इसके अलावा यह पायथन जैसे प्रारूप स्ट्रिंग सिंटैक्स का समर्थन करता है और टाइप जानकारी को कैप्चर करता है ताकि आपको इसे मैन्युअल रूप से प्रदान न करना पड़े:

fmt::print("{}", a);

यह प्रमुख संकलक के साथ परीक्षण किया गया है और प्लेटफार्मों भर में लगातार उत्पादन प्रदान करता है।

अस्वीकरण : मैं इस पुस्तकालय का लेखक हूं।


3

प्रभावी प्रकार अंतर्निहित size_t कार्यान्वयन निर्भर है । सी मानक इसे आकार प्रकार ऑपरेटर द्वारा लौटाए गए प्रकार के रूप में परिभाषित करता है; अहस्ताक्षरित होने और एक प्रकार के अभिन्न प्रकार से अलग होने के कारण, size_t बहुत कुछ भी हो सकता है जो आकार sizeof द्वारा लौटाए जाने वाले अपेक्षित सबसे बड़े मूल्य को समायोजित कर सकता है।

नतीजतन एक आकार_ के लिए इस्तेमाल किया जाने वाला प्रारूप स्ट्रिंग सर्वर के आधार पर भिन्न हो सकता है। यह हमेशा "यू" होना चाहिए, लेकिन एल या डी या शायद कुछ और हो सकता है ...

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


मैं size_tमशीन पर सबसे बड़े अभिन्न प्रकार के लिए अपनी कास्टिंग शांत करूंगा और इस प्रकार से जुड़े प्रारूप स्ट्रिंग का उपयोग करूंगा । मेरा प्रश्न है: क्या कोई ऐसा तरीका है जो मैं स्वच्छ कोड बनाए रखने के दौरान कर सकता हूं (केवल वैध प्रिंटफ प्रारूप स्ट्रिंग त्रुटियों, कोई बदसूरत जाति, आदि के लिए चेतावनी)? मैं एक रैपर लिख सकता हूं जो प्रारूप स्ट्रिंग को बदलता है, लेकिन तब जीसीसी मुझे चेतावनी देने में सक्षम नहीं होगा जब मैंने अपने प्रारूप स्ट्रिंग को वैध रूप से गड़बड़ कर दिया था।
जस्टिन एल।

प्रकार के आकार के परीक्षण के लिए सीपीपी मैक्रोज़ का उपयोग करें; जो मेल खाता है उसके लिए जाएं और प्रारूप स्ट्रिंग निर्दिष्ट करें जो मिलान प्रकार के साथ जाती है।
क्लीयर

0

#include <cstdio>
#include <string>
#include <type_traits>

namespace my{
    template<typename ty>
    auto get_string(ty&& arg){
        using rty=typename::std::decay_t<::std::add_const_t<ty>>;
        if constexpr(::std::is_same_v<char, rty>)
            return ::std::string{1,arg};
        else if constexpr(::std::is_same_v<bool, rty>)
            return ::std::string(arg?"true":"false");
        else if constexpr(::std::is_same_v<char const*, rty>)
            return ::std::string{arg};
        else if constexpr(::std::is_same_v<::std::string, rty>)
            return ::std::forward<ty&&>(arg);
        else
            return ::std::to_string(arg);
    };

    template<typename T1, typename ... Args>
    auto printf(T1&& a1, Args&&...arg){
        auto str{(get_string(a1)+ ... + get_string(arg))};
        return ::std::printf(str.c_str());
    };
};

बाद में कोड में:

my::printf("test ", 1, '\t', 2.0);

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