je_suis_la_vie: (La Vie)
[personal profile] je_suis_la_vie
Надихнувся І. Бігдановим постом...

Що виведе Сішний код наведений нижче?

main() {

        printf(&unix["\021%six\012\0"], (unix)["drop"]+"gun"-0x71);

}

Колись - років чи з п'ять, чи шість тому - читав дуже добрий підручник. Французькою (коли б вона мені ще згодилася? :)), і лише у ньому зустрічав цю задачу. Більше ніде не попадалася, окрім як на одній співбесіді у нашому манюньому Кішлачку. :)


Відповідь літерами білого кольору, щоб прочитати треба виділити текст.

---

Індексні оператори підкоряються тим же арифметичним законам, які діють в арифметиці: від перестановки доданків сума не змінюється; від перестановки співмножників добуток не змінюється.
Це перестановочний (комутативний) закон.


Скажімо у нас є масив "x" з індексом "i" - x[i].

Запис x[i] повністю відповідає запису *(x+i), де ми беремо назву масива "x", яка є адресою початку масива, розіменовуємо його - "*" і вказуємо указкою на місце у масиві під номером "i".
Те ж саме ми отримаємо, написавши *(i+x), і навіть якщо ви запишете i[x] - ви отримаєте той же результат, що і від x[i]. :)

За такі збочення, на мою думку, у практичному програмуванні треба бити до памороків, але для навчання та настанови вони дуже корисні. Тож, продовжуємо. :)))


Константа "unix" це наперед визначена константа будь якого компілятора для UNIX-ової архітектури.
У числовому вираженні це просто "1" (одиничка).
Тож, ми можемо переписати завдання наступним чином:
printf(&1["\021%six\012\0"], (1)["drop"]+"gun"-0x71);


Відповідно до перестановочного закону додавання, що ми згадували вище, 1["\021%six\012\0"] - те ж саме,
що і "\021%six\012\0"[1] а (1)["drop"] - те ж саме, що й "drop"[1].

Тобто &1["\021%six\012\0"] - це адреса символу “%”.
Так ми отримуємо указку на рядок, що починається з "%".
А "drop"[1] - це указка на символ “r”.
Знову спрощуємо наш арифметичний вираз: :)
printf("%six\012\0", 'r'+"gun"-0x71);


На кінці рядка "%six\012\0” бачимо символ '\0' - це "кінець рядка".
Оскільки там у нас перед ним стоїть символ "перехід на новий рядок" - '\012',
то ми можемо символ "кінець рядка" викинути, а представлений у шістнадцятковому
коді "перехід на новий рядок" представити у зручному для людини вигляді - '\n'.
Спрощуємо вираз ще раз:
printf("%six\n", 'r'+"gun"-0x71);

Символ 'r' у шістнадцятковому коді представлений як “0x72”, тож, для показовості прикладу перепишемо його:
printf("%six\n", 0x72+"gun"-0x71);

Від 0x72 відняти 0x71 буде 1. Спростімо вираз іще раз:
printf("%six\n", "gun"+1);

Таким чином "gun"+1 - це просто указка на рядок, що починається з літери "u". Спрощуємо:
printf("%six\n", "un");

На завершення маємо форматний символ "%s", що заміняє будь яку символьну змінну в аргументах функції “printf()”.
У нашому випадку це “un”, а рядок "ix" лише жорстко дописується до відформатованих за допомогою "%s" символів.

Востаннє спрощуємо:
printf("unix\n");

Відповідь: "unix". :)

---
From:
Anonymous( )Anonymous This account has disabled anonymous posting.
OpenID( )OpenID You can comment on this post while signed in with an account from many other sites, once you have confirmed your email address. Sign in using OpenID.
User
Account name:
Password:
If you don't have an account you can create one now.
Subject:
HTML doesn't work in the subject.

Message:

 
Notice: This account is set to log the IP addresses of everyone who comments.
Links will be displayed as unclickable URLs to help prevent spam.

Profile

je_suis_la_vie: (Default)
je_suis_la_vie

September 2017

S M T W T F S
     12
3456789
10 111213141516
17181920212223
2425262728 2930

Style Credit

Expand Cut Tags

No cut tags
Page generated Oct. 19th, 2017 08:06 pm
Powered by Dreamwidth Studios