В компьютерном программировании магическим числом является любое из следующих:
Термин магическое число или магическая константа относится к анти-шаблону использования чисел непосредственно в исходном коде. Это было названо нарушением одного из старейших правил программирования, восходящего к руководствам COBOL , FORTRAN и PL/1 1960-х годов. [1] Использование неназванных магических чисел в коде скрывает намерение разработчиков при выборе этого числа, [2] увеличивает вероятность тонких ошибок (например, каждая ли цифра в числе 3,14159265358979323846 верна и может ли оно быть округлено до 3,14159? [ необходимо разъяснение ] [3] ) и затрудняет адаптацию и расширение программы в будущем. [4] Замена всех значимых магических чисел именованными константами (также называемыми пояснительными переменными) делает программы более простыми для чтения, понимания и поддержки. [5]
Имена, выбранные так, чтобы они были значимыми в контексте программы, могут привести к тому, что код будет легче понять сопровождающему, который не является первоначальным автором (или даже первоначальным автором по прошествии некоторого времени). [6] Примером неинформативно названной константы является int SIXTEEN = 16
, тогда как int NUMBER_OF_BITS = 16
является более описательным.
Проблемы, связанные с магическими «числами», описанные выше, не ограничиваются числовыми типами, и этот термин также применяется к другим типам данных, где объявление именованной константы было бы более гибким и коммуникативным. [1] Таким образом, объявление const string testUserName = "John"
лучше, чем несколько вхождений «магического значения» "John"
в тестовом наборе .
Например, если требуется случайным образом перетасовать значения в массиве, представляющем стандартную колоду игральных карт , этот псевдокод выполнит эту работу, используя алгоритм тасования Фишера-Йетса :
для i от 1 до 52 j := i + randomInt(53 - i) - 1 а.swapEntries(i, j)
где a
— объект массива, функция randomInt(x)
выбирает случайное целое число от 1 до x включительно и swapEntries(i, j)
меняет местами i -ю и j -ю записи в массиве. В предыдущем примере 52
и 53
— магические числа, также явно не связанные друг с другом. Считается лучшим стилем программирования написать следующее:
int deckSize:= 52 для i от 1 до deckSize j := i + randomInt(deckSize + 1 - i) - 1 а.swapEntries(i, j)
Это предпочтительнее по нескольким причинам:
deckSize
во втором примере будет простым изменением в одну строку.dekSize
" вместо " deckSize
" приведет к предупреждению компилятора о том, что dekSize
не объявлено.deckSize
в параметр этой процедуры, тогда как первый пример потребовал бы нескольких изменений.функция shuffle ( int deckSize) для i от 1 до deckSize j := i + randomInt(deckSize + 1 - i) - 1 а.swapEntries(i, j)
Недостатки:
deckSize + 1
во время выполнения может быть медленнее, чем обработка значения "53", хотя большинство современных компиляторов и интерпретаторов заметят, что оно deckSize
было объявлено как константа, и предварительно вычислят значение 53 в скомпилированном коде. Даже если это невозможно, оптимизация цикла переместит сложение так, чтобы оно выполнялось до цикла. Поэтому обычно нет (или незначительно) потери скорости по сравнению с использованием магических чисел в коде. Особенно стоимость отладки и время, необходимое для понимания непояснительного кода, должны быть сопоставлены с крошечной стоимостью вычислений.Этот раздел нуждается в дополнительных цитатах для проверки . ( Март 2010 ) |
В некоторых контекстах использование неназванных числовых констант является общепринятым (и, возможно, «не магическим»). Хотя такое принятие субъективно и часто зависит от индивидуальных привычек кодирования, ниже приведены распространенные примеры:
for (int i = 0; i < max; i += 1)
isEven = (x % 2 == 0)
, где %
есть оператор по модулюcircumference = 2 * Math.PI * radius
, [1] или для вычисления дискриминанта квадратного уравнения какd = b^2 − 4*a*c
(f(x) ** 2 + f(y) ** 2) ** 0.5
какКонстанты 1 и 0 иногда используются для представления булевых значений true и false в языках программирования без булевого типа, таких как старые версии C. Большинство современных языков программирования предоставляют примитивный типboolean
или , поэтому использование 0 и 1 нецелесообразно. Это может быть еще более запутанным, поскольку 0 иногда означает программный успех (когда -1 означает неудачу) и неудачу в других случаях (когда 1 означает успех).bool
В C и C++ 0 представляет нулевой указатель . Как и в случае с булевыми значениями, стандартная библиотека C включает определение макроса NULL
, использование которого поощряется. Другие языки предоставляют определенное значение null
or nil
, и в этом случае не следует использовать альтернативу. Типизированная константа указателя nullptr
была введена в C++11.
Индикаторы формата впервые были использованы в исходном коде ранней версии 7 Unix . [ необходима ссылка ]
Unix был перенесен на один из первых DEC PDP-11 /20, который не имел защиты памяти . Поэтому ранние версии Unix использовали модель перемещаемой ссылки памяти . [7] Версии Unix до шестого издания считывали исполняемый файл в память и переходили на первый нижний адрес памяти программы, относительный адрес ноль. С развитием страничных версий Unix был создан заголовок для описания компонентов исполняемого образа . Кроме того, инструкция ветвления была вставлена как первое слово заголовка, чтобы пропустить заголовок и запустить программу. Таким образом, программа могла быть запущена в старом режиме перемещаемой ссылки памяти (обычном) или в страничном режиме. По мере разработки большего количества исполняемых форматов новые константы добавлялись путем увеличения смещения ветвления . [8]
В исходном коде шестого издания загрузчика программ Unix функция exec() считывала исполняемый ( двоичный ) образ из файловой системы. Первые 8 байт файла были заголовком , содержащим размеры программной (текстовой) и инициализированных (глобальных) областей данных. Кроме того, первое 16-битное слово заголовка сравнивалось с двумя константами , чтобы определить, содержит ли исполняемый образ перемещаемые ссылки на память (обычные), недавно реализованный исполняемый образ с подкачкой только для чтения или разделенный образ инструкции и данных с подкачкой. [9] Не было никакого упоминания о двойной роли константы заголовка, но старший байт константы был, по сути, кодом операции для инструкции ветвления PDP-11 ( восьмеричное 000407 или шестнадцатеричное 0107). Добавление семи к счетчику программ показало, что если эта константа была выполнена , она перейдет к службе Unix exec() по восьмибайтовому заголовку исполняемого образа и запустит программу.
Поскольку шестое и седьмое издания Unix использовали код подкачки, двойная роль константы заголовка была скрыта. То есть, служба exec() считывала данные заголовка исполняемого файла ( meta ) в буфер пространства ядра , но считывала исполняемый образ в пространство пользователя , тем самым не используя функцию ветвления константы. Создание магических чисел было реализовано в компоновщике и загрузчике Unix , а ветвление магических чисел, вероятно, все еще использовалось в наборе автономных диагностических программ , которые поставлялись с шестым и седьмым изданиями. Таким образом, константа заголовка действительно создавала иллюзию и соответствовала критериям magic .
В седьмой версии Unix константа заголовка не проверялась напрямую, а была назначена переменной с меткой ux_mag [10] и впоследствии упоминалась как магическое число . Вероятно, из-за своей уникальности термин магическое число стал обозначать тип исполняемого формата, затем был расширен до типа файловой системы и снова расширен до любого типа файла.
Магические числа распространены в программах во многих операционных системах. Магические числа реализуют строго типизированные данные и являются формой внутриполосной сигнализации для управляющей программы, которая считывает тип(ы) данных во время выполнения программы. Многие файлы имеют такие константы, которые идентифицируют содержащиеся данные. Обнаружение таких констант в файлах является простым и эффективным способом различения многих форматов файлов и может дать дополнительную информацию во время выполнения .
CAFEBABE
. При сжатии с помощью Pack200 байты изменяются на CAFED00D
.47
49
46
38
39
61
) или «GIF87a» ( 47
49
46
38
37
61
)FF
D8
начинаются с и заканчиваются на FF
D9
. Файлы JPEG/ JFIF содержат строку с нулевым символом в конце «JFIF» ( 4A
46
49
46
00
). Файлы JPEG/ Exif содержат строку с нулевым символом в конце «Exif» ( 45
78
69
66
00
), за которой следуют дополнительные метаданные о файле.89
50
4E
47
0D
0A
1A
0A
). Эта подпись содержит различные символы новой строки , позволяющие обнаружить необоснованные автоматические преобразования новой строки, такие как передача файла с использованием FTP с режимом передачи ASCII вместо двоичного режима. [11]4D
54
68
64
23
21
за которым следует путь к интерпретатору , если интерпретатор, скорее всего, будет отличаться от того, из которого был вызван скрипт.7F
за которым следует «ELF» ( 7F
45
4C
46
).25
21
).25
50
44
46
).4D
5A
), инициалов разработчика формата файла Марка Збиковски . Определение допускает 5A
4D
также необычный "ZM" ( ) для dosZMXP, не-PE EXE. [12]19
54
01
19
или 01
19
54
; оба символа представляют собой дату рождения автора, Маршалла Кирка МакКьюсика .55
AA
4A
6F
79
21
) в качестве префикса.49
49
2A
00
. «MM» — для Motorola, которая использует прямой порядок байтов, поэтому магическое число — 4D
4D
00
2A
.FE
FF
для big endian и FF
FE
для little endian). А в Microsoft Windows текстовые файлы UTF-8 часто начинаются с кодировки UTF-8 того же символа, EF
BB
BF
.42
43
).D0
CF
11
E0
) начинаются с , что визуально напоминает слово «DOCFILE0».50
4B
03
04
), где «PK» — инициалы Фила Каца , автора утилиты сжатия DOS PKZIP .37
7A
BC
AF
27
1C
).Утилитная программа Unix file
может считывать и интерпретировать магические числа из файлов, а файл, который используется для анализа информации, называется magic . Утилита Windows TrID имеет схожее назначение.
2A
.52
46
42
от «Remote Frame Buffer»), за которым следует номер версии протокола клиента.FF
53
4D
42
» или "\xFFSMB"
с начала запроса SMB.05
начала запроса (представляющего Microsoft DCE/RPC версии 5), за которым сразу следует 00
или 01
для младшей версии. В запросах MSRPC на основе UDP первый байт всегда 04
.4D
45
4F
57
). Отладочные расширения (используемые для перехвата канала DCOM) начинаются с последовательности байтов "MARB" ( 4D
41
52
42
).19
, представляющее длину заголовка, за которым сразу следует фраза «протокол BitTorrent» в позиции байта 1.E3
представляет клиента eDonkey, C5
представляет eMule и D4
представляет сжатый eMule.0xD9B4BEF9
, которая указывает на основную сеть, в то время как константа 0xDAB5BFFA
указывает на тестовую сеть.80
, а ответ сервера SSLv3 на клиентское приветствие начинается с 16
(хотя это может отличаться).0x63
0x82
0x53
0x63
' в начале раздела опций пакета. Это значение включено во все типы пакетов DHCP.0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
' или " PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
". Префикс предназначен для того, чтобы избежать обработки фреймов серверами и посредниками, которые поддерживают более ранние версии HTTP, но не 2.0.Магические числа широко распространены в функциях и интерфейсах API многих операционных систем , включая DOS , Windows и NetWare :
0000
и 1234
решают, следует ли системе подсчитывать память или нет при перезагрузке, тем самым выполняя холодную или горячую загрузку. Эти значения также используются менеджерами памяти EMM386, перехватывающими запросы на загрузку. [13] BIOS также используют магические значения 55 AA
для определения того, является ли диск загрузочным. [14]Это список ограничений типов хранения данных: [16]
Десятичная дробь | Шестигранник | Описание |
---|---|---|
18,446,744,073,709,551,615 | ФФФ ФФФ ФФФ ФФФ | Максимальное беззнаковое 64-битное значение (2 64 − 1) |
9,223,372,036,854,775,807 | 7ФФФ ФФФФ ФФФФ ФФФ | Максимальное знаковое 64-битное значение (2 63 − 1) |
9,007,199,254,740,992 | 0020 0000 0000 0000 | Наибольшее последовательное целое число двойной точности IEEE 754 (2 53 ) |
4,294,967,295 | ФФФФ ФФФ | Максимальное беззнаковое 32-битное значение (2 32 − 1) |
2,147,483,647 | 7ФФФ ФФФФ | Максимальное знаковое 32-битное значение (2 31 − 1) |
16,777,216 | 0100 0000 | Наибольшее последовательное целое число одинарной точности IEEE 754 (2 24 ) |
65,535 | ФФФФ | Максимальное беззнаковое 16-битное значение (2 16 − 1) |
32,767 | 7ФФФ | Максимальное знаковое 16-битное значение (2 15 − 1) |
255 | ФФ | Максимальное беззнаковое 8-битное значение (2 8 − 1) |
127 | 7Ф | Максимальное знаковое 8-битное значение (2 7 − 1) |
−128 | 80 | Минимальное 8-битное значение со знаком |
−32,768 | 8000 | Минимальное 16-битное значение со знаком |
−2,147,483,648 | 8000 0000 | Минимальное 32-битное значение со знаком |
−9,223,372,036,854,775,808 | 8000 0000 0000 0000 | Минимальное 64-битное значение со знаком |
Можно создавать или изменять глобально уникальные идентификаторы (GUID) так, чтобы они были запоминающимися, но это крайне не рекомендуется, поскольку это ставит под угрозу их силу как почти уникальных идентификаторов. [17] [18] Спецификации для генерации GUID и UUID довольно сложны, что приводит к тому, что они фактически уникальны, если реализованы правильно. [19]
Номера идентификаторов продуктов Microsoft Windows для продуктов Microsoft Office иногда заканчиваются на 0000-0000-0000000FF1CE
(«OFFICE»), например { 90160000-008C-0000-0000-0000000FF1CE
}, идентификатор продукта для «Компонента расширяемости Office 16 Click-to-Run».
Java использует несколько GUID, начинающихся с CAFEEFAC
. [20]
В таблице разделов GUID схемы разбиения GPT загрузочные разделы BIOS используют специальный GUID { 21686148-6449-6E6F-744E-656564454649
} [21] , который не следует определению GUID; вместо этого он формируется с использованием кодов ASCII для строки " Hah!IdontNeedEFI
" частично в прямом порядке байтов . [22]
Значения магической отладки — это определенные значения, записываемые в память во время выделения или освобождения, чтобы впоследствии можно было определить, были ли они повреждены, и сделать очевидным, когда используются значения, взятые из неинициализированной памяти. Память обычно отображается в шестнадцатеричном формате, поэтому часто встречаются запоминающиеся повторяющиеся или шестнадцатеричные значения. Численно нечетные значения могут быть предпочтительными, чтобы процессоры без байтовой адресации выдавали ошибку при попытке использовать их в качестве указателей (которые должны попадать на четные адреса). Значения следует выбирать так, чтобы они находились вдали от вероятных адресов (код программы, статические данные, данные кучи или стек). Аналогично их можно выбирать так, чтобы они не были допустимыми кодами в наборе инструкций для данной архитектуры.
Поскольку маловероятно, хотя и возможно, что 32-разрядное целое число примет это конкретное значение, появление такого числа в отладчике или дампе памяти, скорее всего, указывает на ошибку, например, переполнение буфера или неинициализированную переменную .
Известные и распространённые примеры включают в себя:
Код | Описание |
---|---|
00008123 | Используется в MS Visual C++. Удаленные указатели устанавливаются в это значение, поэтому они выдают исключение, когда используются после; это более узнаваемый псевдоним для нулевого адреса. Он активируется с помощью параметра Security Development Lifecycle (/sdl). [23] |
..FACADE | «Фасад» , используется рядом ОСРВ |
1BADB002 | "1 плохая загрузка" , магическое число заголовка мультизагрузки [24] |
8BADF00D | «Съел плохую еду» . Указывает, что приложение Apple iOS было завершено из-за истечения времени ожидания сторожевого таймера. [25] |
A5A5A5A5 | Используется при разработке встраиваемых систем, поскольку чередующаяся последовательность битов (1010 0101) создает легко распознаваемый шаблон на осциллографах и логических анализаторах . |
A5 | Используется в PHK malloc(3) FreeBSD для отладки, когда /etc/malloc.conf имеет символическую ссылку на "-J" для инициализации всей вновь выделенной памяти, поскольку это значение не является указателем NULL или символом ASCII NUL. |
ABABABAB | Используется отладочной функцией HeapAlloc() от Microsoft для маркировки байтов защиты «нейтральной зоны» после выделения памяти кучи. [26] |
ABADBABE | «Плохая малышка» , используется Apple как магическое число «Boot Zero Block» |
ABBABABE | « ABBA babe» , используется кучей памяти Driver Parallel Lines . |
ABADCAFE | «Плохое кафе» , используется для инициализации всей нераспределенной памяти (Mungwall, AmigaOS ) |
B16B00B5 | «Big Boobs» — ранее требовалось гипервизором Microsoft Hyper -V для использования гостями Linux в качестве верхней половины их «гостевого идентификатора» [27] |
BAADF00D | «Плохая еда» , используется отладочной функцией HeapAlloc() от Microsoft для маркировки неинициализированной выделенной памяти кучи [26] |
BAAAAAAD | "Baaaaaad" , Указывает, что журнал Apple iOS представляет собой снимок всей системы, а не отчет о сбое [25] |
BAD22222 | «Плохо слишком часто» — указывает на то, что приложение Apple iOS VoIP было завершено из-за слишком частого возобновления работы [25] |
BADBADBADBAD | "Плохо, плохо, плохо" , "неинициализированная" память больших систем Берроуза (48-битные слова) |
BADC0FFEE0DDF00D | «Bad coffee odd food» — используется в 64-битных системах IBM RS/6000 для обозначения неинициализированных регистров ЦП. |
BADDCAFE | «Bad cafe» в ОС Solaris от Sun Microsystems обозначает неинициализированную память ядра (KMEM_UNINITIALIZED_PATTERN) |
BBADBEEF | «Плохая говядина» , используется в WebKit для особо неисправимых ошибок [28] |
BEBEBEBE | Используется AddressSanitizer для заполнения выделенной, но не инициализированной памяти [29] |
BEEFCACE | «Говяжий пирог» , используется Microsoft .NET как магическое число в файлах ресурсов |
C00010FF | «Cool off» — указывает на то, что приложение Apple iOS было закрыто операционной системой в ответ на температурное событие [25] |
CAFEBABE | "Cafe babe" , используется Java для файлов классов |
CAFED00D | "Cafe dude" , используется Java для сжатия pack200 |
CAFEFEED | «Cafe feed» , используется ядром отладки Solaris компании Sun Microsystems для маркировки памяти kmemfree() |
CCCCCCCC | Используется библиотекой отладки C++ Microsoft и многими средами DOS для маркировки неинициализированной памяти стека . CC Это код операции прерывания отладочной точки останова INT 3 на процессорах x86. [30] |
CDCDCDCD | Используется отладочной функцией Microsoft C/C++ malloc() для маркировки неинициализированной памяти кучи, обычно возвращается из HeapAlloc() [26] |
0D15EA5E | «Zero Disease» — используется как флаг для обозначения обычной загрузки на консолях GameCube и Wii . |
DDDDDDDD | Используется функцией MicroQuill SmartHeap и функцией отладки Microsoft C/C++ free() для маркировки освобожденной памяти кучи [26] |
DEAD10CC | «Всё заблокировано» . Указывает на то, что приложение Apple iOS было завершено, поскольку оно удерживало системный ресурс во время работы в фоновом режиме [25] |
DEADBABE | «Dead babe» , используется в начале файлов Silicon Graphics IRIX arena |
DEADBEEF | "Dead beef" , широко используемый в системах IBM , таких как RS/6000 , также используемый в классических операционных системах Mac OS , OPENSTEP Enterprise и Commodore Amiga . В Solaris от Sun Microsystems , обозначает освобожденную память ядра (KMEM_FREE_PATTERN) |
DEADCAFE | «Dead cafe» — используется Microsoft .NET как номер ошибки в библиотеках DLL. |
DEADC0DE | «Мертвый код» . Используется в качестве маркера в прошивке OpenWRT для обозначения начала создаваемой файловой системы jffs2 в конце статической прошивки. |
DEADFA11 | «Полный сбой» . Указывает, что приложение Apple iOS было принудительно закрыто пользователем [25] |
DEADF00D | «Мертвая еда» , использовалась Mungwall на Commodore Amiga для обозначения выделенной, но неинициализированной памяти [31] |
DEFEC8ED | "Defeated" , используется для дампов ядра OpenSolaris |
DEADDEAD | «Dead Dead» означает, что пользователь намеренно инициировал аварийный дамп либо из отладчика ядра, либо с клавиатуры в Microsoft Windows. [32] |
D00D2BAD | «Dude, Too Bad», используемый Safari, приводит к сбоям в работе macOS Big Sur. [33] |
D00DF33D | «Dude feed», используется devicetree для обозначения начала заголовков. [34] |
EBEBEBEB | Из SmartHeap от MicroQuill |
FADEDEAD | "Fade dead" , идет в конце, чтобы идентифицировать каждый скрипт AppleScript |
FDFDFDFD | Используется отладочной функцией malloc() от Microsoft C/C++ для маркировки байтов защиты «нейтральной зоны» до и после выделенной динамической памяти [26] и некоторыми отладочными функциями Secure C-Runtime, реализованными Microsoft (например, strncat_s) [35] |
FEE1DEAD | «Feel dead» — используется системным вызовом Linux reboot() |
FEEDFACE | "Feed face" , встречается в двоичных файлах PowerPC Mach-O на платформе Mac OSX компании Apple Inc. В Solaris компании Sun Microsystems обозначает красную зону (KMEM_REDZONE_PATTERN) Используется проигрывателем VLC и некоторыми IP-камерами в протоколе RTP / RTCP , проигрыватель VLC отправляет четыре байта в порядке порядка байтов системы. Некоторые IP-камеры ожидают, что проигрыватель отправит это магическое число, и не начинают поток, если оно не получено. |
FEEEFEEE | "Fee fee" , используется отладочной функцией HeapFree() от Microsoft для маркировки освобожденной памяти кучи. Некоторые близлежащие внутренние значения учета могут также иметь верхнее слово, установленное на FEEE. [26] |
Большинство из них имеют длину 32 бита — размер слова большинства компьютеров с 32-битной архитектурой.
Распространенность этих ценностей в технологиях Microsoft не является совпадением; они подробно обсуждаются в книге Стива Магуайра Writing Solid Code from Microsoft Press . Он приводит ряд критериев для этих ценностей, таких как:
Поскольку они часто использовались для обозначения областей памяти, которые были по сути пустыми, некоторые из этих терминов стали использоваться во фразах, означающих «исчез, прерван, стерт из памяти»; например, «Ваша программа DEADBEEF». [ необходима цитата ]