Существуют ли какие-либо практические приложения для формата% n в семействе printf / scanf?

17
int x;
printf("hello %n World\n", &x);
printf("%d\n", x);
    
задан EvilTeach 09.12.2008 в 18:45
источник
  • +1, потому что он научил меня о% n –  Nathan Fellman 09.12.2008 в 18:57
  • Да, боюсь, я тоже не знал о% n. я сначала ответил о% n для sscanf, но потом заметил, что вы говорите о printf :) +1 –  Johannes Schaub - litb 09.12.2008 в 19:06
  • То же самое происходит здесь. Я никогда не слышал об этом до сегодняшнего дня. Живи учись! –  e.James 09.12.2008 в 19:10

8 ответов

15

Это не так полезно для printf() , но может быть очень полезно для sscanf() , особенно если вы разбираете строку в нескольких итерациях. fscanf() и scanf() автоматически увеличивают свои внутренние указатели на количество введенных данных, но sscanf() этого не делает. Например:

char stringToParse[256];
...
char *curPosInString = stringToParse;  // start parsing at the beginning
int bytesRead;
while(needsParsing())
{
    sscanf(curPosInString, "(format string)%n", ..., &bytesRead);  // check the return value here
    curPosInString += bytesRead;  // Advance read pointer
    ...
}
    
ответ дан Adam Rosenfield 09.12.2008 в 19:02
5

Его можно использовать для выполнения злых дел .

    
ответ дан e.James 09.12.2008 в 19:08
4

Зависит от того, что вы подразумеваете под практикой. Всегда есть другие способы его выполнения (печатайте в строковый буфер с помощью s [n] printf и, например, вычисляйте длину).

Однако

int len;
char *thing = "label of unknown length";
char *value = "value value value"
char *value2="second line of value";
printf ("%s other stuff: %n", thing, &len);
printf ("%s\n%*s, value, len, value2);

должен производить

label of unknown length other stuff: value value value
                                     second line of value

(хотя непроверенный, я не рядом с компилятором C)

Это практически практично как способ согласования вещей, но я бы не хотел видеть его в коде. Есть лучшие способы сделать это.

    
ответ дан The Archetypal Paul 09.12.2008 в 19:02
  • Помимо отсутствующей точки с запятой и закрывающей цитатой это не работает, как указано, потому что общая ширина% * s (включая значение2) установлена ​​равной len, а не количеству начальных пробелов. Таким образом, вам придется либо добавить strlen (value2) в len, либо использовать что-то вроде printf («% s \ n% * s% s», значение, len, «», значение2). –  mweerden 09.12.2008 в 19:28
  • @mweerden, спасибо, это научит меня писать подобные вещи в поезде (я должен был использовать пример с выравниванием по правому краю, который бы сработал :)) Надеюсь, идея все еще ясна. И он по-прежнему слишком «умный» для реального кода. –  The Archetypal Paul 09.12.2008 в 20:32
3

Это довольно эзотерика. Если вам нужно заменить местозаполнитель в сгенерированной строке позже, вы можете захотеть запомнить индекс в середине строки, так что вам не нужно либо сохранять исходный параметр printf, либо анализировать строку.

    
ответ дан Darron 09.12.2008 в 18:53
1

Его можно было бы использовать как быстрый способ получить длины различных подстрок.

    
ответ дан Nathan Fellman 09.12.2008 в 18:57
1
#include <stdio.h>
int main(int argc, char* argv[])
{
    int col10 = (10 - 1);
    int col25 = (25 - 1);

    int pos1 = 0;
    int pos2 = 0;

    printf("    5    10   15   20   25   30\n");

    printf("%s%n%*s%n%*s\n",                     "fried", 
                            &pos1, col10 - pos1, "green",   
                            &pos2, col25 - pos2, "tomatos");


    printf("    ^    ^    ^    ^    ^    ^\n");

    printf("%d %d\n", pos1, pos2);
    printf("%d %d\n", col10 - pos1, col25 - pos2);

    return 0;
}

Я точно что-то упустил. Томатос слишком далеко вправо.

    
ответ дан EvilTeach 09.12.2008 в 20:19
  • Проблема заключается в том, что вы не можете использовать значения, которые назначаются pos1 и pos2 в том же вызове printf. Все аргументы оцениваются перед вызовом, что означает, что col10-pos1 == col10 и col25-pos2 == col25. Правильное позиционирование «зеленого» случайное. Вы также совершили ту же ошибку, что и Павел. –  mweerden 09.12.2008 в 21:22
  • lol, да, я с ним сейчас –  EvilTeach 10.12.2008 в 02:36
0

Вот что-то из кода CRT VS2005:

/* if %n is disabled, we skip an arg and print 'n' */
if ( !_get_printf_count_output() )
{
   _VALIDATE_RETURN(("'n' format specifier disabled", 0), EINVAL, -1);
   break;
}

, который вызывает это:

alt text http://www.shiny.co.il/shooshx/printfn.png

для следующей строки:

    printf ("%s other stuff: %n", thing, &len);

Я предполагаю, что это в основном для того, чтобы избежать того, что @eJames говорит о

    
ответ дан shoosh 09.12.2008 в 19:46
0

вы можете позвонить

int _get_printf_count_output();

, чтобы увидеть, поддерживает ли поддержка% n, или используйте

int _set_printf_count_output( int enable );

Чтобы включить или отключить поддержку формата% n.

из MSDN VS2008

    
ответ дан yur 27.04.2010 в 15:02