Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 01.12.2010, 22:48   #1
fantom_ZET
Пользователь
 
Регистрация: 28.01.2010
Сообщений: 17
По умолчанию Вопрос по куайну на с++

Доброе время.
Первый раз услышал про программы которые печатают свой сорс код. Сначала подумал - легко, попробовал сделать и мое легкомыслие развеялось.
Самая главная проблема избежать "бесконечного углубления" типа:
char *prog = {"char *prog={\"char *prog={\" ... \"}\"}"};
Я нашел рабочий код куайна на С++ вот он:
Код:
#include <stdio.h>
void main ( ) {
    char * s = "#include <stdio.h>%cvoid main ( ) {%c%cchar * s = %c%s%c;%c%cprintf ( s, 0xA, 0xA, 0x9, 0x22, s, 0x22, 0xA, 0x9, 0xA );%c}";
    printf ( s, 0xA, 0xA, 0x9, 0x22, s, 0x22, 0xA, 0x9, 0xA );
}
Увидев этот код я так и не понял каким образом решена проблема.
Например что за %с и %с%с в символьном массиве???
Почему это ... char * s = %c%s%c ...?
0xA, 0xA, 0x9, 0x22, s, 0x22, 0xA, 0x9, 0xA - что это?))
Помогите разобраться.

Последний раз редактировалось fantom_ZET; 01.12.2010 в 22:51.
fantom_ZET вне форума Ответить с цитированием
Старый 02.12.2010, 00:15   #2
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Ну смотрите. С синтаксисом функции printf ведь знакомы? Будем для простоты априорно считать, что знакомы.
Во-первых, что это у нас за char * s такая, и для чего она нужна?
А собственно, вот для чего. Функция printf может в качестве первого аргумента принимать не только строковой литерал (как это чаще всего делается), но и указатель на Си-строку (тип char*) (и вообще, строковой литерал - лишь тривиальный частный случай этого самого char*). Поэтому следующие три варианта записи эквивалентны:
Код:
printf("Value of Pi is %f\n", 3.1415926);
char * s1 = "Value of Pi is %f\n"; //Указатель на строковой литерал, хранящийся в стеке
printf(s1, 3.1415926);
char * s2 = new char[strlen(s1) + 1]; //Указатель на строку, память выделяется в куче
strcpy(s2, s1);
printf(s2, 3.1415926);
Поэтому определенную здесь строку char * s = ""; мы можем спокойно запихать в качестве аргумента printf. И когда мы это сделаем, все управляющие последовательности типа %с %d %s %f и т.д. будут интерпретированы как это обычно происходит в printf.
Теперь по поводу 0xA 0x9 и прочих. Это коды символов по таблице ASCII. К примеру, 0xA - это символ перевода на новую строку, 0x9 - горизонтальный Tab, 0x22 - кавычка ".
Итак, чтобы напечатать, к примеру, две строки из кода, с переводом на следующую строку:
Код:
#include <stdio.h>
void main() {
понадобится следующий код:
Код:
#include <stdio.h>
void main() {
  char * s = "#include <stdio.h>%cvoid main () {%c";
  printf(s, 0xA, 0xA);
}
В результате выведутся те самые две строки, и между ними будет подставлен символ char(0xA), т.е. символ с кодом 0xA - символ перевода строки.
Идем дальше. Нетрудно вывести и прочие строки, вроде printf и закрывающей скобки. Но еще нужно как-то вывести саму строку s и это делается очень просто. То, что находится между кавычек, а равно и сами кавычки (а со всем остальным проблем нет - засунули в строку и забыли, никакой рекурсии они не вызовут), мы выведем в printf. Кавычки выведем с помощью символа 0x22, а саму строку с помощью %s. Итак, вот так вот мы выводим почти весь код, за исключением содержимого строки (кавычки выводим также):
Код:
#include <stdio.h>
void main ( ) {
    char * s = "#include <stdio.h>%cvoid main ( ) {%c%cchar * s = %c%s%c;%c%cprintf ( s, 0xA, 0xA, 0x9, 0x22, 0x22, 0xA, 0x9, 0xA );%c}";
    printf ( s, 0xA, 0xA, 0x9, 0x22, 0x22, 0xA, 0x9, 0xA );
}
Тут ничего принципиально нового, кроме тех самых символов кавычек.
И наконец финальным аккордом - засовываем в printf вывод строки s - всего лишь "s, " в серединку строки форматирования и один аргумент в список аргументов printf.
Код:
#include <stdio.h>
void main ( ) {
    char * s = "#include <stdio.h>%cvoid main ( ) {%c%cchar * s = %c%s%c;%c%cprintf ( s, 0xA, 0xA, 0x9, 0x22, s, 0x22, 0xA, 0x9, 0xA );%c}";
    printf ( s, 0xA, 0xA, 0x9, 0x22, s, 0x22, 0xA, 0x9, 0xA );
}
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 02.12.2010, 00:21   #3
JeyKip
Форумчанин
 
Регистрация: 18.09.2009
Сообщений: 133
По умолчанию

немного не вовремя опубликовал...уже предоставлена информация...

Последний раз редактировалось JeyKip; 02.12.2010 в 00:23. Причина: Сообщение не содержало новой инфорации
JeyKip вне форума Ответить с цитированием
Старый 02.12.2010, 02:28   #4
fantom_ZET
Пользователь
 
Регистрация: 28.01.2010
Сообщений: 17
По умолчанию

Гром, огромное спасибо вам. В голове теперь ясное солнце..
fantom_ZET вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Вопрос по БД!!!!!!!!! L0102591 Помощь студентам 0 16.01.2010 11:52
Вопрос по mySQL + Вопрос по RichEdit HTL Общие вопросы Delphi 4 01.01.2010 20:22
Вопрос наверное про функции, а так точно даже не знаю про что. (Вопрос начинющего #6) Albert2008 Общие вопросы Delphi 4 21.08.2008 15:33
вопрос по сокетам и общение как в ICQ.Сложный вопрос... Руслантус Общие вопросы C/C++ 2 12.08.2008 21:10