C में% n प्रारूप निर्दिष्टकर्ता का उपयोग क्या है?


125

%nC में प्रारूप विनिर्देशक का उपयोग क्या है ? क्या कोई उदाहरण के साथ समझा सकता है?


25
फाइन मैनुअल पढ़ने की ललित कला क्या बन गई है?
जेन्स

8
मुझे लगता है कि असली सवाल यह है कि इस तरह के विकल्प का सूत्र क्या है ? कोई क्यों छपे छपी संख्याओं का मूल्य जानना चाहता है बहुत कम लिखता है वह मूल्य सीधे मेमोरी में जाता है। यह डेवलपर्स की तरह ऊब गया था और कर्नेल में बग को पेश करने का फैसला किया था
जिया चेन

इसलिए बायोनिक ने इसे जाने दिया।
सॉलिडक

1
यह वास्तव में एक वैध सवाल है, और एक यह है कि ठीक मैनुअल जवाब नहीं देंगे; यह पता चला है कि %nबनाता है printfगलती से ट्यूरिंग-पूर्ण और आप जैसे उस में Brainfuck लागू कर सकते हैं, को देखने के github.com/HexHive/printbf और oilshell.org/blog/2019/02/07.html#appendix-a-minor-sublanguages
जॉन फ्रेज़र

जवाबों:


147

कुछ भी नहीं छपा। तर्क एक हस्ताक्षरित इंट का सूचक होना चाहिए, जहां अब तक लिखे गए पात्रों की संख्या संग्रहीत है।

#include <stdio.h>

int main()
{
  int val;

  printf("blah %n blah\n", &val);

  printf("val = %d\n", val);

  return 0;

}

पिछला कोड प्रिंट करता है:

blah  blah
val = 5

1
आप उल्लेख करते हैं कि तर्क एक हस्ताक्षरित इंट का सूचक होना चाहिए, फिर आपने अपने उदाहरण में एक अहस्ताक्षरित int का उपयोग किया (शायद सिर्फ एक टाइपो)।
बटा

1
@AndrewS: क्योंकि फ़ंक्शन वेरिएबल के मान को संशोधित करेगा।
जैक

3
@ जैक intहमेशा हस्ताक्षरित है।
jamesdlin

1
@jamesdlin: मेरी गलती है। मुझे क्षमा करें .. मुझे नहीं पता था कि मैंने कहाँ पढ़ा है।
जैक

1
किसी कारण के लिए नमूना नोट के साथ त्रुटि उठाता है n format specifies disabled। क्या कारण है?
जॉनी_ड

186

इनमें से अधिकांश उत्तर बताते हैं कि क्या %n करता है (जो कुछ भी नहीं छापना है और इस प्रकार मुद्रित वर्णों की संख्या को एक intचर में लिखना है ), लेकिन अभी तक किसी ने वास्तव में इसका उपयोग करने का कोई उदाहरण नहीं दिया है। यहाँ एक है:

int n;
printf("%s: %nFoo\n", "hello", &n);
printf("%*sBar\n", n, "");

प्रिंट होगा:

hello: Foo
       Bar

फू और बार के साथ गठबंधन किया। (यह %nविशेष रूप से उदाहरण के लिए उपयोग किए बिना ऐसा करना तुच्छ है , और सामान्य तौर पर एक व्यक्ति हमेशा उस पहली printfकॉल को तोड़ सकता है :

int n = printf("%s: ", "hello");
printf("Foo\n");
printf("%*sBar\n", n, "");

क्या थोड़ा जोड़ा सुविधा कुछ गूढ़ का उपयोग करने के लायक है %n(और संभवतः त्रुटियों का परिचय देते हुए) बहस के लिए खुला है।)


3
ओह माय - यह एक दिए गए फ़ॉन्ट में स्ट्रिंग के पिक्सेल आकार की गणना करने का एक चरित्र-आधारित संस्करण है!

क्या आप समझा सकते हैं कि क्यों & n और * की आवश्यकता है। क्या वे दोनों इशारा कर रहे हैं?
एंड्रयू एस

9
@AndrewS &nएक पॉइंटर ( &ऑपरेटर का पता है); एक पॉइंटर आवश्यक है क्योंकि C पास-पास-वैल्यू है, और पॉइंटर के बिना, printfवैल्यू को संशोधित नहीं कर सकता है n%*sमें उपयोग printfप्रारूप स्ट्रिंग एक प्रिंट %sविनिर्देशक (इस मामले में रिक्त स्ट्रिंग "") एक का उपयोग कर क्षेत्र चौड़ाई के nअक्षर। मूल printfसिद्धांतों की व्याख्या मूल रूप से इस प्रश्न (और उत्तर) के दायरे से बाहर है; मैं printfप्रलेखन पढ़ने या SO पर अपना अलग सवाल पूछने की सलाह दूंगा।
jamesdlin

3
उपयोग-मामला दिखाने के लिए धन्यवाद। मुझे समझ में नहीं आता है कि लोग मूल रूप से मैन्युअल रूप से एसओ में कॉपी-पेस्ट करते हैं और कभी-कभी इसे फिर से बनाते हैं। हम इंसान हैं और सब कुछ एक कारण से किया जाता है, जिसे हमेशा एक उत्तर में समझाया जाना चाहिए। "कुछ नहीं करता है" यह कहने जैसा है "शांत शब्द का अर्थ है शांत" - लगभग बेकार ज्ञान।
the_endian

1
@PSkocik अप्रत्यक्ष स्तर के अतिरिक्त स्तर को जोड़ने के बिना यह पर्याप्त है और त्रुटि-प्रवण है।
jamesdlin

18

मैंने वास्तव में %nविनिर्देशक के कई व्यावहारिक वास्तविक विश्व उपयोगों को नहीं देखा है , लेकिन मुझे याद है कि इसका इस्तेमाल कुछ समय पहले एक प्रारूप स्ट्रिंग हमले के साथ oldschool प्रिंटफ कमजोरियों में किया गया था ।

कुछ इस तरह

void authorizeUser( char * username, char * password){

    ...code here setting authorized to false...
    printf(username);

    if ( authorized ) {
         giveControl(username);
    }
}

जहां एक दुर्भावनापूर्ण उपयोगकर्ता उपयोगकर्ता नाम को पैरामीटर स्ट्रिंग के रूप में प्रिंटफ में पास होने का फायदा उठा सकता है और कॉल स्टैक के माध्यम से जाने के लिए या w / e के संयोजन का उपयोग कर सकता है %d, %cऔर फिर एक सच्चे मूल्य के लिए अधिकृत चर को संशोधित कर सकता है।

हाँ, यह एक गूढ़ उपयोग है, लेकिन हमेशा यह जानने के लिए उपयोगी है कि सुरक्षा छेद से बचने के लिए डेमन लिखते समय? : डी


1
प्रारूप स्ट्रिंग के %nरूप में अनियंत्रित इनपुट स्ट्रिंग का उपयोग करने से बचने के लिए अधिक कारण हैं printf
कीथ थॉम्पसन

13

से यहाँ हम देखते हैं कि यह अब तक मुद्रित अक्षरों की संख्या संग्रहीत करता है।

n तर्क एक पूर्णांक के लिए एक संकेतक होगा, जिसमें इस fprintf()फ़ंक्शन द्वारा अब तक आउटपुट को लिखी गई बाइट्स की संख्या को कॉल किया जाता है। कोई तर्क नहीं बदला है।

एक उदाहरण उपयोग होगा:

int n_chars = 0;
printf("Hello, World%n", &n_chars);

n_charsतब का मान होगा 12


10

अब तक सभी उत्तर उस के बारे में हैं %n, लेकिन यह नहीं कि कोई भी इसे पहली जगह में क्यों चाहेगा। मुझे लगता है कि यह कुछ हद तक उपयोगी है sprintf/ snprintf, जब आपको बाद में टूटने या परिणामस्वरूप स्ट्रिंग को संशोधित करने की आवश्यकता हो सकती है, क्योंकि संग्रहीत मूल्य परिणामी स्ट्रिंग में एक सरणी सूचकांक है। यह एप्लिकेशन बहुत अधिक उपयोगी है, हालांकि, परिवार sscanfमें विशेष रूप से चूंकि कार्यों scanfकी संख्या संसाधित नहीं है, लेकिन खेतों की संख्या वापस नहीं आती है।

एक और सच में हैकिश उपयोग एक छद्म लॉग -10 को मुफ्त में एक ही समय में एक और ऑपरेशन के हिस्से के रूप में एक नंबर प्रिंट करते हुए मिल रहा है।


+1 का उल्लेख करने के लिए उपयोग करता है %n, हालांकि मैं "सभी उत्तरों ..." के बारे में अलग-अलग भीख मांगता हूं। = P
jamesdlin

1
बुरे लोग आपके
प्रिंटफ

6
@noloader: ऐसा कैसे? उपयोग की %n एक हमलावर को असुरक्षा की बिल्कुल शून्य खतरा है। %nवास्तव में गलत ढंग से बदनाम प्रारूप तर्क के रूप में एक प्रारूप स्ट्रिंग के बजाय एक संदेश स्ट्रिंग पारित करने की बेवकूफी अभ्यास पर संबंधित है। बेशक यह स्थिति कभी नहीं उठती है जब %nवास्तव में एक जानबूझकर प्रारूप स्ट्रिंग का उपयोग किया जा रहा है।
आर .. गिटहब स्टॉप हेल्पिंग आईसीई

% n आपको मेमोरी में लिखने की अनुमति देता है। मुझे लगता है कि आप यह मान रहे हैं कि हमलावर उस सूचक को नियंत्रित नहीं करता है (मैं गलत हो सकता है)। यदि हमलावर पॉइंटर को नियंत्रित करता है (यह प्रिंट करने के लिए सिर्फ एक अन्य पैरामीटर है), तो वह 4 बाइट्स का लेखन कर सकता है। वह लाभ कर सकता है / नहीं यह एक अलग कहानी है।
jww

8
@noloader: यह संकेत के किसी भी उपयोग के बारे में सच है। लिखने के लिए कोई भी "बुरे लोग धन्यवाद" नहीं कहते हैं *p = f();। ऐसा क्यों होना चाहिए %n, जो सूचक द्वारा इंगित की गई वस्तु के परिणामस्वरूप लिखने का सिर्फ एक और तरीका है, सूचक को खतरनाक मानने के बजाय "खतरनाक" माना जाए?
आर .. गिटहब स्टॉप हेल्पिंग ICE

10

%nवसीयत से जुड़े तर्क को एक के रूप में माना जाएगा int*और उस बिंदु पर मुद्रित कुल वर्णों की संख्या से भरा है printf


9

दूसरे दिन मैंने खुद को ऐसी स्थिति में पाया जहाँ मैं %nअच्छी तरह से अपनी समस्या को हल करूँगा। मेरे पहले के उत्तर के विपरीत , इस मामले में, मैं एक अच्छा विकल्प तैयार नहीं कर सकता।

मेरे पास एक GUI नियंत्रण है जो कुछ निर्दिष्ट पाठ प्रदर्शित करता है। यह नियंत्रण उस पाठ के भाग को बोल्ड (या इटैलिक, या रेखांकित, आदि) में प्रदर्शित कर सकता है, और चरित्र सूचकांकों को शुरू करने और समाप्त करने के लिए मैं निर्दिष्ट कर सकता हूं कि कौन सा भाग निर्दिष्ट करें।

मेरे मामले में, मैं नियंत्रण के साथ पाठ उत्पन्न कर snprintfरहा हूं, और मैं चाहूंगा कि किसी एक विकल्प को बोल्ड बनाया जाए। इस प्रतिस्थापन के शुरुआती और अंत सूचक ढूंढना गैर-तुच्छ है क्योंकि:

  • स्ट्रिंग में कई प्रतिस्थापन हैं, और प्रतिस्थापन में से एक मनमाना है, उपयोगकर्ता-निर्दिष्ट पाठ। इसका मतलब यह है कि मैं जिस प्रतिस्थापन की परवाह करता हूं, उसके लिए एक पाठ्य खोज करना संभावित रूप से अस्पष्ट है।

  • प्रारूप स्ट्रिंग स्थानीयकृत किया जा सकता है, और यह $स्थिति प्रारूप प्रारूप के लिए POSIX एक्सटेंशन का उपयोग कर सकता है । इसलिए प्रारूप निर्दिष्ट करने वाले के लिए मूल प्रारूप स्ट्रिंग की खोज स्वयं गैर-तुच्छ है।

  • स्थानीयकरण पहलू का अर्थ यह भी है कि मैं आसानी से कई कॉल में प्रारूप स्ट्रिंग को तोड़ नहीं सकता snprintf

इसलिए एक विशेष प्रतिस्थापन के आसपास सूचकांकों को खोजने का सबसे सरल तरीका यह होगा:

char buf[256];
int start;
int end;

snprintf(buf, sizeof buf,
         "blah blah %s %f yada yada %n%s%n yakety yak",
         someUserSpecifiedString,
         someFloat,
         &start, boldString, &end);
control->set_text(buf);
control->set_bold(start, end);

मैं आपको उपयोग के मामले में +1 दूंगा। लेकिन आप एक ऑडिट को विफल करने जा रहे हैं, इसलिए आपको संभवतः बोल्ड टेक्स्ट की शुरुआत और अंत को चिह्नित करने के लिए एक और तरीका तैयार करना चाहिए। यह तीनों की तरह लगता है snprintfजबकि रिटर्न वैल्यू की जांच करना ठीक काम करेगा क्योंकि snprintfलिखे गए अक्षरों की संख्या वापस आती है। हो सकता है कि कुछ इस तरह: int begin = snprintf(..., "blah blah %s %f yada yada", ...);और int end = snprintf(..., "%s", ...);और फिर पूंछ: snprintf(..., "blah blah");
jww

3
@jww कई snprintfकॉल के साथ समस्या यह है कि प्रतिस्थापन को अन्य स्थानों में फिर से व्यवस्थित किया जा सकता है, इसलिए उन्हें इस तरह नहीं तोड़ा जा सकता है।
jamesdlin

उदाहरण के लिए धन्यवाद। लेकिन क्या आप ऐसा नहीं कर सकते हैं, जैसे कि उत्पादन से पहले क्षेत्र को बोल्ड बनाने के लिए टर्मिनल कंट्रोल सीक्वेंस लिखें और उसके बाद एक सीक्वेंस लिखें? यदि आप टर्मिनल नियंत्रण अनुक्रमों को हार्डकोड नहीं करते हैं, तो आप उन्हें स्थितिगत (पुन: प्रयोज्य) भी बना सकते हैं।
PSkocik

1
@PSkocik यदि आप किसी टर्मिनल पर आउटपुट कर रहे हैं। अगर आप एक Win32 रिच-एडिट कंट्रोल के साथ काम कर रहे हैं, तो आप तब तक मदद नहीं करेंगे, जब तक आप वापस जाकर टर्मिनल कंट्रोल सीक्वेंस को पार्स नहीं कर सकते। यह भी माना जाता है कि आप बाकी प्रतिस्थापित पाठ में टर्मिनल नियंत्रण अनुक्रमों का सम्मान करना चाहते हैं; यदि आप नहीं करते हैं, तो आपको उन लोगों को फ़िल्टर करना होगा या उनसे बचना होगा। मैं यह नहीं कह रहा हूं कि इसके बिना करना असंभव है %n; मैं दावा कर रहा हूं कि %nविकल्पों की तुलना में उपयोग अधिक सरल है।
jamesdlin

1

यह कुछ भी नहीं छापता है। इसका उपयोग यह पता लगाने के लिए किया जाता है %nकि प्रारूप स्ट्रिंग में दिखाई देने से पहले कितने वर्ण प्रिंट किए गए थे , और आउटपुट जो int को दिए गए थे:

#include <stdio.h>

int main(int argc, char* argv[])
{
    int resultOfNSpecifier = 0;
    _set_printf_count_output(1); /* Required in visual studio */
    printf("Some format string%n\n", &resultOfNSpecifier);
    printf("Count of chars before the %%n: %d\n", resultOfNSpecifier);
    return 0;
}

(के लिए प्रलेखन_set_printf_count_output )


0

यह उस printf()फ़ंक्शन में अब तक मुद्रित वर्णों की संख्या का मान संग्रहीत करेगा ।

उदाहरण:

int a;
printf("Hello World %n \n", &a);
printf("Characters printed so far = %d",a);

इस कार्यक्रम का आउटपुट होगा

Hello World
Characters printed so far = 12

जब मैं आपको कोड देने की कोशिश करता हूं तो यह मुझे देता है: हैलो वर्ल्ड कैरेक्टर अब तक छपे = 36 ,,,,, 36 क्यों! मैं एक विंडोज़ मशीन में 32 बिट GCC का उपयोग करता हूं।
सिना कारवंडी

-6

% n C99 है, VC ++ के साथ काम नहीं करता है।


2
%nC89 में मौजूद है। यह MSVC के साथ काम नहीं करता है क्योंकि Microsoft ने सुरक्षा चिंताओं के लिए इसे डिफ़ॉल्ट रूप से अक्षम कर दिया था; _set_printf_count_outputइसे सक्षम करने के लिए आपको पहले कॉल करना होगा । (
मेरलिन

नहीं, C89 इस सुविधा / पिछले दरवाजे को परिभाषित नहीं करता है। देखें K & R + ANSI-C amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/… ?? टिप्पणियों के लिए URL-tagger कहाँ है ??
user411313

4
तुम बस गलत हो। यह के printfएंड आर, 2 डी संस्करण के परिशिष्ट बी के टेबल बी -1 ( रूपांतरण) में स्पष्ट रूप से सूचीबद्ध है । (मेरी प्रति का पृष्ठ २४४) या आईएसओ सी ९ ० विनिर्देशन का भाग (.९ .६.१ (पृष्ठ १३४) देखें।
jamesdlin

एंड्रॉइड ने% n स्पेसियर को भी हटा दिया।
jww

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