Прочитав новость» Код интерпретатора Perl официально перенесен на GitHub "На ресурсе LINUX.ORG.RU я решил взглянуть на репозиторий Perl 5, который сейчас находится на GitHub. Удивительно, насколько аккуратно и качественно его перенесли, сохранив не только абсолютно всю 32-летнюю историю проекта, но и отчеты об ошибках (входящие в Issues), патчи (входящие в PR), релизы и ветки.
Надпись " 32 года назад «Рядом с файлами вызывает непроизвольную улыбку.
Чем еще заняться в этот унылый пятничный вечер, когда на улице неприятно моросит дождь и снег, а все уличные дорожки увязли в осенней слякоти? Правильно, красные глаза! Итак, ради эксперимента и интереса я решил взять и собрать древний Perl на современной машине x86_64 последней версии.
GCC 9.2.0 в качестве компилятора.
Может ли такой старый код выдержать испытание временем?
Демонстрация работы твм , один из первых оконных менеджеров для X Window System в современном дистрибутиве Arch Linux.
Чтобы сделать его полностью аутентичным и некромантичным, я развернул виртуальную машину с голыми крестиками и оконным менеджером.
твм , который тоже родом из 1987 года.
Кто знает, может быть Ларри Уолл Я написал свой Perl, используя именно твм , так сказать передовые технологии то время.
Используемый дистрибутив — Arch Linux. Просто потому, что в его репозитории есть несколько полезных вещей, которые мне потом пригодились.
Итак, начнем!
Содержание:
1. Подготовка среды 2. Конфигурация исходного кода 3. Ошибки файла грамматики Yacc 4. Ошибки при компиляции кода на «С» 5. Исправьте некоторые ошибки сегментации.6. Подведем итоги
1. Подготовка среды
Сначала устанавливаем на развернутую операционную систему на виртуальной машине весь джентльменский набор утилит и компиляторов, необходимых для сборки и редактирования исходного кода: GCC , делать , вим , мерзавец , БДБ и т. д. Некоторые из них уже установлены, а другие доступны в мета-пакете.базовая разработка , его необходимо установить, если он не установлен.
Как только среда готова к действию, мы получаем копию исходного кода Perl 32-летней давности!
Благодаря возможностям Git нам не нужно тащить кучу файлов, чтобы добраться до самого первого релиза проекта:$ git clone https://github.com/Perl/perl5/ --depth=1 -b perl-1.0
* commit 8d063cd8450e59ea1c611a2f4f5a21059a2804f1 (grafted, HEAD, tag: perl-1.0)
Commit: Larry Wall <[email protected]>
CommitDate: Fri Dec 18 00:00:00 1987 +0000
a "replacement" for awk and sed
Мы скачиваем лишь небольшой объем данных, и в результате репозиторий с исходным кодом первой версии Perl занимает всего 150 КБ.
В то темное и густое время не было такой элементарной вещи, как автоинструменты ( какое счастье! ), но в корне репозитория лежит скрипт Настроить .
В чем дело? Но дело в том, что Ларри Уолл является изобретателем таких скриптов, которые позволяли генерировать Makefiles для самых разнообразных UNIX-машин того времени.
Как говорится одноимённая статья об этих сценариях в английской Википедии Ларри Уолл предоставил файл за три года до написания Perl. Настроить с каким-то своим софтом, например, программой для чтения новостей р-н .
Впоследствии Perl не стал исключением, и для его сборки был использован скрипт, уже проверенный на многих машинах.
Позже эту идею подхватили и другие разработчики, например, программисты из Trolltech. Они использовали аналогичный скрипт для настройки сборки своего фреймворка Qt, который многие путают с настроить от автоинструменты .
Именно зоопарк подобных скриптов от разных разработчиков послужил толчком к созданию инструмента для их упрощенной и автоматической генерации.
2. Конфигурация исходного кода
Скрипт Настроить «старой школы», что видно уже из его Шебанг 'y, который содержит пробел: $ cat Configure | head -5
#! /bin/sh
#
# If these # comments don't work, trim them. Don't worry about any other
# shell scripts, Configure will trim # comments from them for you.
#
Судя по комментарию, оказывается, что были оболочки, в скриптах которых не было возможности оставлять комментарии! Ситуация с пространством выглядит необычно, но когда-то это было нормой, подробнее смотрите по ссылкам Здесь .
Самое главное, что для современных интерпретаторов оболочки не имеет значения, есть там пробел или нет.
Хватит лирики, пора переходить к делу! Запускаем скрипт и видим интересное предположение, которое оказывается не совсем верным: $ .
/Configure (I see you are using the Korn shell. Some ksh's blow up on Configure, especially on exotic machines. If yours does, try the Bourne shell instead.) Beginning of configuration questions for perl kit. Checking echo to see how to suppress newlines. .
using -n.
Type carriage return to continue. Your cursor should be here-->
Удивительно, но скрипт интерактивный и содержит огромную кучу различной справочной информации.
Модель взаимодействия с пользователем построена на диалогах, анализируя ответы на которые скрипт меняет свои параметры, в соответствии с которыми в дальнейшем будет генерировать Makefiles. Мне лично было интересно проверить, все ли команды оболочки на своих местах? Locating common programs.
expr is in /bin/expr.
sed is in /bin/sed.
echo is in /bin/echo.
cat is in /bin/cat.
rm is in /bin/rm.
mv is in /bin/mv.
cp is in /bin/cp.
tr is in /bin/tr.
mkdir is in /bin/mkdir.
sort is in /bin/sort.
uniq is in /bin/uniq.
grep is in /bin/grep.
Don't worry if any of the following aren't found.
test is in /bin/test.
egrep is in /bin/egrep.
I don't see Mcc out there, offhand.
Видимо, раньше такого не было.
Интересно, за что отвечает утилита Максс , который не удалось найти? Самое забавное, что этот скрипт, в лучших хакерских традициях того времени, полон дружелюбного юмора.
Сейчас почти никогда не увидишь что-то подобное: Is your "test" built into sh? [n] (OK to guess) OK
Checking compatibility between /bin/echo and builtin echo (if any).
They are compatible. In fact, they may be identical.
Your C library is in /lib/libc.a. You're normal.
Extracting names from /lib/libc.a for later perusal.done
Hmm. Looks kind of like a USG system, but we'll see.
Congratulations. You aren't running Eunice.
It's not Xenix.
Nor is it Venix.
Checking your sh to see if it knows about # comments.
Your sh handles # comments correctly.
Okay, let's see if #! works on this system.
It does.
Checking out how to guarantee sh startup.
Let's see if '#!/bin/sh' works.
Yup, it does.
На большинство вопросов я ответил значением по умолчанию или тем, что мне предложил сценарий.
Особенно порадовал и удивил запрос флагов для компилятора и компоновщика: Any additional cc flags? [none]
Any additional ld flags? [none]
Там можно написать что-нибудь интересное, например: -м32 для сборки 32-битного исполняемого файла или библиотеки, необходимой при компоновке.
К последнему вопросу сценария: Now you need to generate make dependencies by running "make depend".
You might prefer to run it in background: "make depend > makedepend.out &"
It can take a while, so you might not want to run it right now.
Run make depend now? [n] y
Я ответил положительно.
Древняя полезность зависимость , Судя по ее страница в Википедии, был создан очень рано проект Афина , чтобы упростить работу с Makefiles. Этот проект дал нам X Window System, Kerberos, Zephyr и повлиял на многие другие вещи, которые мы знаем сегодня.
Все это здорово, но откуда эта утилита в современной среде Linux? Он уже давно никем и нигде не используется.
Но если внимательно посмотреть в корень репозитория, то окажется, что Ларри Уолл написал его замещающую версию скрипта, которую он для нас аккуратно распаковал и выполнил скрипт конфигурации.
Производительность сделать зависимостью закончилось некоторыми странными ошибками: .
/makedepend: command substitution: line 82: unexpected EOF while looking for matching `'' .
/makedepend: command substitution: line 83: syntax error: unexpected end of file .
/makedepend: command substitution: line 82: unexpected EOF while looking for matching `'' .
/makedepend: command substitution: line 83: syntax error: unexpected end of file
Возможно, именно они и стали причиной проблемы, из-за которой сгенерированные Makefile были немного разжеваны: $ make
make: *** No rule to make target '<built-in>', needed by 'arg.o'.
Stop.
Погрузитесь в дебри замысловатых утилит с лапшой в скорлупе.
зависимость Мне очень не хотелось и я решил присмотреться к Makefiles, в которых выявилась странная закономерность: arg.o: arg.c
arg.o: arg.h
arg.o: array.h
arg.o: <built-in>
arg.o: cmd.h
arg.o: <command-line>
arg.o: config.h
arg.o: EXTERN.h
.
array.o: arg.h array.o: array.c array.o: array.h array.o: <built-in> array.o: cmd.h array.o: <command-line> array.o: config.h array.o: EXTERN.h .
Видимо какая-то утилита неправильно вставила свои аргументы в выхлоп.
Берем в руки утилиту для топора СЭД Решил немного исправить это дело: $ sed -i '/built-in/d' Makefile
$ sed -i '/command-line/d' Makefile
Удивительно, но трюк сработал, и Makefiles заработали как надо! << Skip to content
3. Ошибки файла грамматики Yacc
Было бы просто невероятно, если бы можно было без проблем взять и собрать код 32-летней давности.К сожалению, чудес не бывает. Изучая дерево исходного кода, я наткнулся на файл perl.y , который представляет описания грамматики утилиты якк , который в современных дистрибутивах уже давно заменен на бизон .
Скрипт по пути /usr/bin/yacc , просто звонит бизон в режиме совместимости якк .
Но эта совместимость не полная и при обработке этого файла высыпается огромная куча ошибок, исправлять которые я не знаю и не очень хочу, потому что есть альтернативное решение, о котором я узнал только недавно.
Всего год или два назад Хелио Киссини де Кастро, разработчик KDE, проделывал аналогичную работу и адаптировал KDE 1, 2 и Qt 1, 2 к современным средам и компиляторам.
Я заинтересовался его творчеством, скачал исходники проектов, но при сборке наткнулся на нечто подобное подводный камень из-за несовместимости якк И бизон , которые использовались для сборки древней версии метакомпилятора мок .
Впоследствии мне удалось найти решение этой проблемы в виде замены бизон в коммунальную службу по акк (Berkeley Yacc), которая оказалась совместимой со старыми грамматиками для якк и был доступен во многих дистрибутивах Linux. Простая замена якк на по акк.
в системе сборки меня тогда выручило, правда ненадолго, ведь чуть позже в новых версиях по акк.
все еще нарушил совместимость с якк , прерывая отладку, связанную с сущностью yydebug .
Поэтому мне пришлось сделать немного правильная грамматика коммунальные услуги.
Итак, стратегия исправления ошибок сборки в файле такая: perl.y было предсказано предыдущим опытом: установите утилиту по акк , изменять якк на по акк.
во всех Makefile, потом вырезаем отовсюду yydebug .
Эти действия решили все проблемы с этим файлом, ошибки исчезли и компиляция продолжилась.
4. Ошибки при компиляции кода на «С»
Древний код Perl был полон ужасов, таких как давно устаревшие и забытые обозначения определений функций, такие как K&R: format(orec,fcmd)
register struct outrec *orec;
register FCMD *fcmd;
{
.
}
STR *
hfetch(tb,key)
register HASH *tb;
char *key;
{
.
}
/*VARARGS1*/
fatal(pat,a1,a2,a3,a4)
char *pat;
{
fprintf(stderr,pat,a1,a2,a3,a4);
exit(1);
}
Подобные особенности были обнаружены, например, в коде Microsoft Word 1.1а , что тоже довольно древнее.
Первый стандарт языка программирования C, получивший название C89, появился всего два года спустя.
Современные компиляторы умеют работать с таким кодом, но некоторые IDE не умеют парсить такие определения и подсвечивать их как синтаксические ошибки, я, например, раньше так грешил Создатель Qt до того, как парсинг кода был перенесен в библиотеку libclang .
Компилятор GCC 9.2.0, выдав огромное количество предупреждений, взялся скомпилировать древний код первой версии Perl. Листы предупреждений были настолько большими, что чтобы добраться до ошибки, приходилось пролистывать несколько страниц выхлопа вверх.
К моему удивлению, большинство ошибок компиляции были типичными и в основном касались предопределённых определений, которые играли роль флагов для сборки.
Запуск современного компилятора GCC 9.2.0 и отладчика GDB 8.3.1 в оконном менеджере.
твм и эмулятор терминала xterm .
Определять СТДСТДИО Ларри Уолл экспериментировал с какой-то древней и нестандартной библиотекой языка программирования «С», и под определением ОТЛАДКА там была отладочная информация с пресловутым yydebug , о котором я говорил выше.
По умолчанию эти флажки были включены.
Отключив их в файле perl.h а добавив несколько забытых определений, мне удалось значительно сократить количество ошибок.
Другой тип ошибки — это переопределение теперь стандартизированных функций стандартной библиотеки и уровня POSIX. Проект имеет свой собственный маллок() , setenv() и другие субъекты, создавшие конфликты.
В паре мест статические функции были определены без объявлений.
Со временем составители стали более строго относиться к этой проблеме и превратил предупреждение в ошибку .
И напоследок пара забытых заголовков, где бы мы были без них?
К моему удивлению, патч для кода 32-летней давности оказался настолько крошечным, что его можно воспроизвести целиком здесь: diff --git a/malloc.c b/malloc.c
index 17c3b27.a1dfe9c 100644
--- a/malloc.c
+++ b/malloc.c
@@ -79,6 +79,9 @@ static u_int nmalloc[NBUCKETS];
#include <stdio.h>
#endif
+static findbucket(union overhead *freep, int srchlen);
+static morecore(register bucket);
+
#ifdef debug
#define ASSERT(p) if (!(p)) botch("p"); else
static
diff --git a/perl.h b/perl.h
index 3ccff10.e98ded5 100644
--- a/perl.h
+++ b/perl.h
@@ -6,16 +6,16 @@
*
*/
-#define DEBUGGING
-#define STDSTDIO /* eventually should be in config.h */
+//#define DEBUGGING
+//#define STDSTDIO /* eventually should be in config.h */
#define VOIDUSED 1
#include "config.h"
-#ifndef BCOPY
-# define bcopy(s1,s2,l) memcpy(s2,s1,l);
-# define bzero(s,l) memset(s,0,l);
-#endif
+//#ifndef BCOPY
+//# define bcopy(s1,s2,l) memcpy(s2,s1,l);
+//# define bzero(s,l) memset(s,0,l);
+//#endif
#include <stdio.h>
#include <ctype.h>
@@ -183,11 +183,11 @@ double atof();
long time();
struct tm *gmtime(), *localtime();
-#ifdef CHARSPRINTF
- char *sprintf();
-#else
- int sprintf();
-#endif
+//#ifdef CHARSPRINTF
+// char *sprintf();
+//#else
+// int sprintf();
+//#endif
#ifdef EUNICE
#define UNLINK(f) while (unlink(f) >= 0)
diff --git a/perl.y b/perl.y
index 16f8a9a.1ab769f 100644
--- a/perl.y
+++ b/perl.y
@@ -7,6 +7,7 @@
*/
%{
+#include <stdlib.h>
#include "handy.h"
#include "EXTERN.h"
#include "search.h"
diff --git a/perly.c b/perly.c
index bc32318.fe945eb 100644
--- a/perly.c
+++ b/perly.c
@@ -246,12 +246,14 @@ yylex()
static bool firstline = TRUE;
retry:
+#ifdef DEBUGGING
#ifdef YYDEBUG
if (yydebug)
if (index(s,'\n'))
fprintf(stderr,"Tokener at %s",s);
else
fprintf(stderr,"Tokener at %s\n",s);
+#endif
#endif
switch (*s) {
default:
diff --git a/stab.c b/stab.c
index b9ef533.9757cfe 100644
--- a/stab.c
+++ b/stab.c
@@ -7,6 +7,7 @@
*/
#include <signal.h>
+#include <errno.h>
#include "handy.h"
#include "EXTERN.h"
#include "search.h"
diff --git a/util.h b/util.h
index 4f92eeb.95cb9bf 100644
--- a/util.h
+++ b/util.h
@@ -28,7 +28,7 @@ void prexit();
char *get_a_line();
char *savestr();
int makedir();
-void setenv();
+//void setenv();
int envix();
void notincl();
char *getval();
Отличный результат для кода 32-летней давности! Ошибка связывания неопределенная ссылка на `crypt' было исправлено добавлением директивы в Makefile -lcrypt соответствующая библиотека библиотека libcrypt , после чего я наконец получил заветный исполняемый файл интерпретатора Perl: $ file perl
perl: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fd952ceae424613568530b3a2ca88ebd6477e0ae, for GNU/Linux 3.2.0, not stripped
<< Skip to content
5. Исправьте некоторые ошибки сегментации.
После почти беспроблемной компиляции удача отвернулась от меня.
Сразу после запуска собранного интерпретатора Perl я получил несколько странных ошибок и Segmentation error в конце: $ .
/perl -e 'print "Hello World!\n";'
Corrupt malloc ptr 0x2db36040 at 0x2db36000
Corrupt malloc ptr 0x2db36880 at 0x2db36800
Corrupt malloc ptr 0x2db36080 at 0x2db36040
Corrupt malloc ptr 0x2db37020 at 0x2db37000
Segmentation fault (core dumped)
Щелкая исходный текст по фразе Поврежденный malloc , оказалось, что вместо системы маллок() Вызывается какой-то специальный распределитель 1982 года.
Интересно, что один из строковых литералов в исходном коде гласит: Беркли , а в комментарии рядом - Калтех .
Сотрудничество между этими университетами тогда, видимо, было очень крепким.
В общем, я закомментировал этот хакерский аллокатор и пересобрал исходный код. Ошибки повреждения памяти исчезли, но ошибка сегментации осталась.
Это значит, что это было не так и теперь нам нужно раскрыть отладчик.
Запустив программу под БДБ Я обнаружил, что сбой происходит при вызове функции создания временного файла.
мктемп() из библиотеки: $ gdb --args .
/perl -e 'print "Hello, World!\n";'
(gdb) r
Starting program: /home/exl/perl5/perl -e print\ \"Hello\ World\!\\n\"\;
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7cd20c7 in __gen_tempname () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff7cd20c7 in __gen_tempname () from /usr/lib/libc.so.6
#1 0x00007ffff7d71577 in mktemp () from /usr/lib/libc.so.6
#2 0x000055555556bb08 in main ()
Кстати, компоновщик ранее жаловался на эту функцию.
Не компилятор, а компоновщик, что меня удивило: /usr/bin/ld: perl.o: in function `main':
perl.c:(.
text+0x978c): warning: the use of `mktemp' is dangerous, better use `mkstemp' or `mkdtemp'
Первая мысль, которая наверняка пришла вам в голову — заменить небезопасная функция мктемп() на мкстемп() , что я и сделал.
Предупреждение компоновщика исчезло, но ошибка Segmentation error на этом месте все равно осталась, только теперь она была в функции мкстемп() .
Поэтому теперь вам нужно очень внимательно посмотреть на тот участок кода, который связан с этой функцией.
Там я обнаружил довольно странную вещь, которая выделена в этом фрагменте: char *e_tmpname = "/tmp/perl-eXXXXXX";
int main(void) {
mktemp(e_tmpname);
e_fp = f_open(e_tmpname, "w");
.
}
Оказывается мктемп() пытается изменить литерал по маске, которая находится в разделе .
родата , который заведомо обречен на провал.
Или 32 года назад это было еще приемлемо, найдено в коде и даже как-то работало?
Конечно, замена символ *e_tmpname на символ e_tmpname[] исправил эту ошибку сегментации, и я смог получить то, на что потратил весь вечер: $ .
/perl -e 'print "Hello World!\n";' $ Hello, World! $ .
/perl -e '$a = 5; $b = 6.3; $c = $a+$b; print $c."\n";' $ 11.3000000000000007 $ .
/perl -v
$Header: perly.c,v 1.0 87/12/18 15:53:31 root Exp $
Patch level: 0
Мы проверили выполнение из командной строки, а как насчет файла? Я загрузил из Интернета первый найденный мной «Hello World» для языка программирования Perl: ################# test.pl
#!/usr/bin/perl
#
# The traditional first program.
# Strict and warnings are recommended.
use strict;
use warnings;
# Print a message.
print "Hello, World!\n";
Потом я попробовал его запустить, но, увы, меня снова ждала ошибка Segmentation. На этот раз совсем в другом месте: $ gdb --args .
/perl test.pl
(gdb) r
Starting program: /home/exl/perl5/perl test.pl
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7d1da75 in __strcpy_sse2_unaligned () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff7d1da75 in __strcpy_sse2_unaligned () from /usr/lib/libc.so.6
#1 0x00005555555629ea in yyerror ()
#2 0x0000555555568dd6 in yyparse ()
#3 0x000055555556bd4f in main ()
В функции yyerror() Обнаружился следующий интересный момент, вот исходный фрагмент: // perl.y
char *tokename[] = {
"256",
"word",
"append",
.
// perl.c yyerror(s) char *s; { char tmpbuf[128]; char *tname = tmpbuf; if (yychar > 256) { tname = tokename[yychar-256]; // ??? if (strEQ(tname,"word")) strcpy(tname,tokenbuf); // Oops! else if (strEQ(tname,"register")) sprintf(tname,"$%s",tokenbuf); // Oops! .
Опять же ситуация аналогична той, о которой я писал выше.
Данные в разделе снова изменены .
родата .
Возможно это просто опечатки из-за копирования-вставки и вместо этого tname хотел написать tmpbuf ? Или действительно в этом есть какой-то скрытый смысл? В любом случае замена символ *имя токена[] на символьное имя токена[][32] очищает ошибку сегментации, и Perl сообщает нам следующее: $ .
/perl test.pl
syntax error in file test.pl at line 7, next token "strict"
Execution aborted due to compilation errors.
Оказывается, он не любит всякие новомодные используйте строгий , вот что он пытался нам сказать! Если вы удалите или закомментируете эти строки в файле, программа запустится: $ .
/perl test.pl
Hello, World!
<< Skip to content
6. Подведем итоги
По сути, я добился своей цели и заставил древний код 1987 года не только компилироваться, но и работать в современной среде Linux. Несомненно, осталась еще большая куча различных ошибок сегментации, возможно, связанных с размером указателя на 64-битной архитектуре.Все это можно подчистить, проведя несколько вечеров с отладчиком наготове.
Но это не очень приятное и довольно утомительное занятие.
Ведь этот эксперимент изначально планировался как развлечение для скучного вечера, а не как полноценная работа, которая будет завершена.
Есть ли практическая польза от предпринятых действий? Возможно, когда-нибудь какой-нибудь цифровой археолог наткнется на эту статью и найдет ее полезной.
Но в реальном мире даже опыт, полученный в результате таких исследований, на мой взгляд, не очень ценен.
Если кому интересно, выкладываю комплект из двух патчей.
Первый исправляет ошибки компиляции, а второй исправляет некоторые ошибки сегментации.
P.S. Спешу разочаровать поклонников деструктивные остроты , здесь это не работает. Возможно, версия Perl слишком стара для таких развлечений.
П.
П.
С.
Всего наилучшего и хороших выходных.
Спасибо пользователю каваи_неко позади небольшое исправление .
Обновление от 28 октября 2019 г.
: Пользователь форума LINUX.ORG.RU под ником utf8нигде , принес в твоем комментарии На эту статью есть довольно интересные ссылки, информация из которых не только проясняет ситуацию с изменяемыми строковыми литералами, но и даже рассматривает проблему использования описанной выше функции.
мктемп() ! Позвольте мне процитировать эти источники, в которых говорится о различных несовместимостях между нестандартизированным «K&R C» и «GNU C»:
Несовместимость GCC Существует несколько примечательных несовместимостей между версиями C GNU C и K&R (не ISO).Флаг компилятора -fwritable-строки был объявлен устаревшим в GCC 3.4 и окончательно удален в GCC 4.0.GCC обычно делает строковые константы доступными только для чтения.
Если используется несколько строковых констант идентичного вида, GCC сохраняет только одну копию строки.
Одним из последствий является то, что вы не можете позвонить мктемп со строковым константным аргументом.
Функция мктемп всегда изменяет строку, на которую указывает его аргумент. Другое следствие состоит в том, что sscanf не работает в некоторых системах, если в качестве строки управления форматом или ввода передается строковая константа.
Это потому что sscanf неправильно пытается записать в строковую константу.
Так же fscanf и сканирование .
Лучшим решением этих проблем является изменение используемой программы.
голец -переменные-массивы со строками инициализации для этих целей вместо строковых констант. Но если это невозможно, вы можете использовать -fwritable-строки флаг, который предписывает GCC обрабатывать строковые константы так же, как это делает большинство компиляторов C. Источник: Использование коллекции компиляторов GNU (GCC 3.3) Официальное руководство .
Обоснование ANSI C | Строковые литералы СТеги: #*nix #История ИТ #C++ #Аномальное программирование #perl #некромантия #некромантия #цифровая археология #некрофилия #perl 5
-
Перекресток. Главы 9 И 10
19 Oct, 24 -
Процессоры Nehalem Будут Называться Core I7
19 Oct, 24 -
Субстики #83
19 Oct, 24