Jaki jest użytek ze specyfikatora formatu %n W C?

Jakie jest zastosowanie specyfikacji formatu %n W C? Czy ktoś może wyjaśnić przykładem?

 105
Author: Cristian Ciupitu, 2010-08-04

10 answers

Nic nie zostało wydrukowane. Argument musi być wskaźnikiem do podpisanej liczby int, gdzie przechowywana jest liczba znaków zapisanych do tej pory.

#include <stdio.h>

int main()
{
  int val;

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

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

  return 0;

}

Poprzedni kod drukuje:

blah  blah
val = 5
 133
Author: Starkey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-21 17:29:35

Większość z tych odpowiedzi wyjaśnia, co %n czy (czyli nic nie wydrukować i zapisać liczbę znaków wydrukowanych do tej pory do zmiennej int), ale do tej pory nikt tak naprawdę nie podał przykładu tego, co używa. Oto jeden:

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

Wydrukuje:

hello: Foo
       Bar

Z Foo i Bar wyrównane. (Jest to trywialne, aby to zrobić bez użycia %n dla tego konkretnego przykładu, i ogólnie zawsze można rozbić ten pierwszy printf wywołanie:

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

Czy nieco dodana wygoda jest warta użycia czegoś ezoterycznego jak %n (i ewentualnie wprowadzenia błędów) jest otwarta do dyskusji.)

 163
Author: jamesdlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-12 22:06:51

Nie widziałem zbyt wielu praktycznych zastosowań specyfikatora %n, ale pamiętam, że był on używany w oldschoolowych lukach printf z atakiem strun formatu jakiś czas temu.

Coś, co poszło tak

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

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

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

Gdzie złośliwy użytkownik mógł skorzystać z parametru username przekazywanego do printf jako ciąg formatujący i użyć kombinacji %d, %c lub w / e, aby przejść przez stos wywołań, a następnie zmodyfikować zmienną / align = "left" /

Tak, to Ezoteryczne zastosowanie, ale zawsze warto wiedzieć, gdy piszesz demona, aby uniknąć luk w zabezpieczeniach? : D

 14
Author: Xzhsh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-21 11:45:24

Z tutaj widzimy, że przechowuje liczbę wydrukowanych do tej pory znaków.

n argument jest wskaźnikiem do liczby całkowitej, do której zapisywana jest liczba bajtów zapisanych na wyjściu dotychczas przez to wywołanie do jednej z funkcji fprintf(). Żaden argument nie jest konwertowany.

Przykładowe użycie to:

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

n_chars wtedy będzie miała wartość 12.

 13
Author: KLee1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-26 23:03:35

Argument związany z %n będzie traktowany jako int* i wypełniony liczbą wszystkich znaków wydrukowanych w tym momencie w printf.

 9
Author: Evan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-03 22:15:13

Jak na razie wszystkie odpowiedzi są na to, że %n robi, ale nie po co ktokolwiek miałby tego chcieć. Uważam, że jest to nieco przydatne z sprintf/snprintf, Kiedy może być konieczne późniejsze rozbicie lub zmodyfikowanie wynikowego ciągu, ponieważ przechowywana wartość jest indeksem tablicy do wynikowego ciągu. Ta aplikacja jest o wiele bardziej przydatna, jednak z sscanf, zwłaszcza, że funkcje z rodziny scanf nie zwracają liczby przetworzonych znaków, ale liczby pól.

Inny naprawdę lame use to uzyskanie pseudo-log10 za darmo w tym samym czasie podczas drukowania numeru w ramach innej operacji.

 5
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-04 12:16:04

Pewnego dnia znalazłem się w sytuacji, w której ładnie rozwiążę mój problem. W przeciwieństwie do mojej wcześniejszej odpowiedzi , w tym przypadku, nie mogę wymyślić dobrej alternatywy.

Mam kontrolkę GUI, która wyświetla określony tekst. Ta kontrolka może wyświetlać część tekstu pogrubioną (lub kursywą, lub podkreśloną, itd.), i mogę określić, która część, określając indeksy znaków początkowych i końcowych.

W moim przypadku generuję tekst do kontrolki za pomocą snprintf i Chciałbym, aby jedna z podstawień była pogrubiona. Znalezienie indeksów początkowych i końcowych do tej podstawienia jest nietrywialne, ponieważ:

  • Łańcuch zawiera wiele podstawień, a jedną z podstawień jest dowolny, określony przez użytkownika tekst. Oznacza to, że wyszukiwanie tekstowe substytucji, na której mi zależy, jest potencjalnie niejednoznaczne.

  • Łańcuch formatu może być zlokalizowany i może używać rozszerzenia POSIX $ dla formatu pozycyjnego / align = "left" / Dlatego wyszukiwanie oryginalnego ciągu formatu dla samych specyfikatorów formatu jest nietrywialne.

  • Aspekt lokalizacji oznacza również, że nie mogę łatwo podzielić ciągu formatowania na wiele wywołań do snprintf.

Dlatego najprostszym sposobem znalezienia indeksów wokół konkretnej substytucji byłoby wykonanie:

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);
 2
Author: jamesdlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:26

Nic nie drukuje. Jest on używany, aby dowiedzieć się, ile znaków zostało wydrukowanych, zanim %n pojawiło się w łańcuchu formatowania, i wypisać je do podanego 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;
}

(Dokumentacja dla _set_printf_count_output)

 1
Author: Merlyn Morgan-Graham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-21 11:48:35

Zapisze wartość liczby znaków wydrukowanych do tej pory w tej funkcji printf().

Przykład:

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

Wyjście tego programu będzie

Hello World
Characters printed so far = 12
 1
Author: Sudhanshu Mishra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-21 11:49:40

%N to C99, nie działa z VC++.

 -5
Author: user411313,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-04 22:33:25