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


102

मैं दुर्भाग्य से काफी एक परियोजना के लिए वीएस 2010 का उपयोग कर अटक गया है, और निम्नलिखित कोड अभी भी गैर-मानक कंपाइलर कंपाइलर का उपयोग नहीं करता है देखा है:

#include <stdio.h>
#include <stdlib.h>

int main (void)
{
    char buffer[512];

    snprintf(buffer, sizeof(buffer), "SomeString");

    return 0;
}

(त्रुटि के साथ संकलन विफल रहता है: C3861: 'स्नप्रिंट': पहचानकर्ता नहीं मिला)

मुझे याद है कि यह वीएस 2005 के साथ वापस आ रहा है और यह देखकर हैरान हूं कि यह अभी भी तय नहीं हुआ है।

क्या किसी को पता है कि क्या Microsoft के पास अपने मानक C पुस्तकालयों को वर्ष 2010 में स्थानांतरित करने की कोई योजना है?


1
... या आप सिर्फ "#define snprintf _snprintf" कर सकते हैं
फर्नांडो गोंजालेज सांचेज़

4
... आप कर सकते हैं, लेकिन दुर्भाग्य से _sprintprint () snprintf () के समान नहीं है क्योंकि यह शून्य समाप्ति की गारंटी नहीं देता है।
एंडी क्राउवेल

ठीक है, इसलिए आपको _snprintf () का उपयोग करने से पहले इसे शून्य पर याद करना होगा। इसके अलावा मैं आपसे सहमत हूं। MSVC के तहत विकास भयानक है। त्रुटियां नरक के रूप में भी भ्रमित कर रही हैं।
उल्लू

जवाबों:


88

लघु कहानी: Microsoft ने आखिरकार Visual Studio 2015 में snprintf को लागू कर दिया है। पहले के संस्करणों में आप इसे नीचे के रूप में अनुकरण कर सकते हैं।


दीर्घ संस्करण:

यहाँ snprintf के लिए अपेक्षित व्यवहार है:

int snprintf( char* buffer, std::size_t buf_size, const char* format, ... );

अधिकांश buf_size - 1वर्णों पर एक बफर में लिखता है । परिणामी वर्ण स्ट्रिंग को शून्य वर्ण के साथ समाप्त किया जाएगा, जब तक buf_sizeकि शून्य न हो। यदि buf_sizeशून्य है, तो कुछ भी नहीं लिखा है और bufferएक अशक्त सूचक हो सकता है। रिटर्न वैल्यू उन वर्णों की संख्या है, जिन्हें असीमित शब्द मानकर लिखा गया होगा buf_size, न कि समाप्त होने वाले अशक्त चरित्र को गिनते हुए।

विजुअल स्टूडियो 2015 से पहले की रिलीज़ों का एक अनुरूप कार्यान्वयन नहीं था। इसके बजाय गैर-मानक एक्सटेंशन हैं जैसे _snprintf()(जो अतिप्रवाह पर नल-टर्मिनेटर नहीं लिखता है) और _snprintf_s()(जो अशक्त-समाप्ति को लागू कर सकता है, लेकिन वर्णों की संख्या के बजाय अतिप्रवाह पर -1 लिखता है)।

वीएस 2005 और ऊपर के लिए सुझाए गए कमबैक:

#if defined(_MSC_VER) && _MSC_VER < 1900

#define snprintf c99_snprintf
#define vsnprintf c99_vsnprintf

__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
{
    int count = -1;

    if (size != 0)
        count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
    if (count == -1)
        count = _vscprintf(format, ap);

    return count;
}

__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
{
    int count;
    va_list ap;

    va_start(ap, format);
    count = c99_vsnprintf(outBuf, size, format, ap);
    va_end(ap);

    return count;
}

#endif

यह हमेशा एक 0 के साथ स्ट्रिंग को समाप्त नहीं करेगा जो एक अतिप्रवाह पर आवश्यक है। दूसरा अगर c99_vsnprintf में होना चाहिए: if (count == -1) {if (size> 0) str [size-1] = 0; गिनती = _vscprintf (प्रारूप, एपी); }
लोथर

1
@ लोथर: बफर हमेशा शून्य-समाप्त होता है। MSDN के अनुसार: "यदि स्ट्रिंग ट्रंकेशन को _TRUNCATE पास करके सक्षम किया जाता है, तो ये फ़ंक्शन केवल उसी स्ट्रिंग की ज्यादा कॉपी करेंगे जो फिट होगी, गंतव्य बफ़र को शून्य-टर्मिनेटेड छोड़ कर, और सफलतापूर्वक वापस आएगा"।
वैलेंटाइन मिला

2
जून 2014 तक, विजुअल स्टूडियो में अभी भी "फुल" C99 सपोर्ट नहीं है, यहां तक ​​कि अपडेट 2 के साथ भी। यह ब्लॉग MSVC 2013 के लिए C99 सपोर्ट को संक्षिप्त रूप देता है। स्निपरफ () पारिवारिक कार्य अब C ++ 11 मानक का एक हिस्सा है। , MSVC C ++ 11 कार्यान्वयन में क्लैंग और जीसीसी से पीछे है!
fnisi

2
VS2014 के साथ, स्निपर और वर्नप्रिंट के साथ C99 मानक जोड़े गए हैं। ब्लॉगs.msdn.com/b/vcblog/archive/2014/06/18/… देखें ।
वल्केन रैवेन

1
मिकेल लेपिस्टो: वाक़ई? मेरे लिए _sprintprint तभी काम करता है जब मैं _CRT_SECURE_NO_WARNINGS सक्षम करता हूं। इस काम के आसपास उस कदम के बिना ठीक काम करता है।
FvD

33

snprintfC89 का हिस्सा नहीं है। यह केवल C99 में मानक है। Microsoft की C99 को समर्थन देने वाली कोई योजना नहीं है

(लेकिन यह C ++ 0x में भी मानक है ...!)

वर्कअराउंड के लिए नीचे अन्य उत्तर देखें।


5
यह एक अच्छा समाधान नहीं है, हालांकि ... क्योंकि वहाँ snprintf और _snprintf व्यवहार में अंतर हैं। _snprintf अपर्याप्त बफर स्पेस से निपटने पर मंद टर्मिनेटर को मंद तरीके से हैंडल करता है।
एंड्रयू

7
@DeadMG - गलत। cl.exe / Tc विकल्प का समर्थन करता है, जो कंपाइलर को C कोड के रूप में फ़ाइल संकलित करने का निर्देश देता है। इसके अलावा, मानक सी पुस्तकालयों के एक संस्करण के साथ MSVC जहाज।
एंड्रयू

3
@DeadMG - हालांकि, यह C90 स्टैंडर्ड के साथ-साथ C99 के कुछ बिट्स को सपोर्ट करता है, जिससे यह C कंपाइलर बन जाता है।
एंड्रयू

15
केवल तभी यदि आप 1990 और 1999 के बीच रहते हैं।
प्यूपी

6
-1, Microsoft का _snprintfएक असुरक्षित कार्य है जो अलग तरीके से व्यवहार करता है snprintf(यह जरूरी नहीं कि एक शून्य टर्मिनेटर जोड़ सकता है), इसलिए इस उत्तर में दी गई सलाह भ्रामक और खतरनाक है।
इंटरजेन

8

यदि आपको रिटर्न वैल्यू की आवश्यकता नहीं है, तो आप सिर्फ स्नप्रिंट को _snprintf_s के रूप में परिभाषित कर सकते हैं

#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)

3

मेरा मानना ​​है कि विंडोज समकक्ष है sprintf_s


7
sprintf_sसे अलग व्यवहार करता है snprintf
इंटरजेन

विशेष रूप से स्प्रिंटफ़_ डॉक्स कहते हैं, "यदि बफर पाठ मुद्रित होने के लिए बहुत छोटा है, तो बफर खाली स्ट्रिंग पर सेट है"। इसके विपरीत Snprintf आउटपुट में एक छोटा स्ट्रिंग लिखता है।
एंड्रयू बैनब्रिज

2
@AndrewBainbridge - आपने दस्तावेज़ को काट दिया। पूर्ण वाक्य है "यदि बफर मुद्रित किए जा रहे पाठ के लिए बहुत छोटा है, तो बफर को खाली स्ट्रिंग पर सेट किया जाता है और अमान्य पैरामीटर हैंडलर लागू किया जाता है।" अमान्य पैरामीटर हैंडल के लिए डिफ़ॉल्ट व्यवहार आपके प्रोग्राम को समाप्त करने के लिए है। यदि आप _ परिवार के साथ संबंध बनाना चाहते हैं तो आपको snprintf_s और _TRUNCATE ध्वज का उपयोग करने की आवश्यकता है। हां, यह दुर्भाग्यपूर्ण है कि _ कार्य फालतू का सुविधाजनक तरीका नहीं देते हैं। दूसरी ओर, _ फ़ंक्शंस बफर बफर साइज़ के लिए टेम्प्लेट मैजिक का उपयोग करते हैं, और यह उत्कृष्ट है।
ब्रूस डॉसन


1

मैंने @Valentin Milea के कोड की कोशिश की, लेकिन मुझे एक्सेस उल्लंघन की त्रुटियाँ मिली हैं। केवल एक चीज जो मेरे लिए काम कर रही थी वह थी इंसाइडिंग कोडिंग का कार्यान्वयन: http://asprintf.insanecoding.org/

विशेष रूप से, मैं VC ++ 2008 की विरासत कोड के साथ काम कर रहा था। इन्सेन कोडिंग के कार्यान्वयन से (ऊपर लिंक से डाउनलोड किया जा सकता है), मैं तीन फ़ाइलों का उपयोग: asprintf.c, asprintf.hऔर vasprintf-msvc.c। अन्य फाइलें MSVC के अन्य संस्करणों के लिए थीं।

[संपादित करें] पूर्णता के लिए, उनकी सामग्री इस प्रकार है:

asprintf.h:

#ifndef INSANE_ASPRINTF_H
#define INSANE_ASPRINTF_H

#ifndef __cplusplus
#include <stdarg.h>
#else
#include <cstdarg>
extern "C"
{
#endif

#define insane_free(ptr) { free(ptr); ptr = 0; }

int vasprintf(char **strp, const char *fmt, va_list ap);
int asprintf(char **strp, const char *fmt, ...);

#ifdef __cplusplus
}
#endif

#endif

asprintf.c:

#include "asprintf.h"

int asprintf(char **strp, const char *fmt, ...)
{
  int r;
  va_list ap;
  va_start(ap, fmt);
  r = vasprintf(strp, fmt, ap);
  va_end(ap);
  return(r);
}

vasprintf-msvc.c:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "asprintf.h"

int vasprintf(char **strp, const char *fmt, va_list ap)
{
  int r = -1, size = _vscprintf(fmt, ap);

  if ((size >= 0) && (size < INT_MAX))
  {
    *strp = (char *)malloc(size+1); //+1 for null
    if (*strp)
    {
      r = vsnprintf(*strp, size+1, fmt, ap);  //+1 for null
      if ((r < 0) || (r > size))
      {
        insane_free(*strp);
        r = -1;
      }
    }
  }
  else { *strp = 0; }

  return(r);
}

उपयोग ( test.cपागल कोडन द्वारा प्रदान किया गया हिस्सा ):

#include <stdio.h>
#include <stdlib.h>
#include "asprintf.h"

int main()
{
  char *s;
  if (asprintf(&s, "Hello, %d in hex padded to 8 digits is: %08x\n", 15, 15) != -1)
  {
    puts(s);
    insane_free(s);
  }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.