Почему так? Казалось бы, две строки об одном и том же
const char *kodirovka[] = ... -работает.
const char **kodirovka = ... -не работает.
Это как это "об одном и том же"? Ничего общего эти варианты не имеют. Первый вариант объявляет массив указателей. Каждый указатель в этом массиве инициализируется указателем на свой строковый литерал - все в порядке. Второй вариант объявляет некий указатель. Чем он инициализируется? На что должен указывать этот указатель???
"Спасти" второй вариант можно так
const char **kodirovka = (const char *[]) {
"windows-1251", // (0)
"utf-8", // (1)
};
Это уже будет компилироваться. Но это будет полностью эквивалентно первому варианту. То есть нет смысла заменять первый вариант на этот.
И в аргументах функции
const char *set_kod(const char **kodirovka);
массив определён по второму варианту, нерабочему, но работает. Моё предположение: когда память под массив уже выделена, то можно без квадратных скобок, а если ещё не выделена, то нужны квадратные скобки.
Нет. Список параметров функции - это совсем другой контекст, в котором эта запись имеет совсем другой смысл, ничего общего не имеющий с исходным вариантом. В списке параметров функции
const char **kodirovka полностью эквивалентно
const char *kodirovka[]. За пределами списка параметров функции такой эквивалентности нет даже отдаленно. Поэтому сравнивать поведение при объявлении глобальных переменных с поведением в списке параметров функции смысла нет.
Переменная const char *kod в парсере и в серверной обёртке парсера используется в трёх функциях, и я хотел сделать её глобальной. Но не получилось. В программе выше есть 4 метки, ими помечены кусочки кода, причастные к вопросу. Пробовал активировать каждую из них по отдельности. Глобальные (METKA-1, METKA-2) не работают.
Проблема в инициализаторе.
В языке С (в отличии от С++) нет динамической инициализации для переменных со статическим классом памяти, т.е. в т.ч. для глобальных переменных. Все переменные со статическим классом памяти должны инициализироваться константными выражениями, т.е. константами времени компиляции. У вас это правило нарушено.
А локальные (МЕТКА-3, МЕТКА-4) работают. Почему так? Подозреваю, что это баг компилятора.
Никакого бага компилятора тут нет. Требование константности инициализатора не распространяется на переменные с автоматическим классом памяти, т.е. на ваши локальные переменные.
Вопрос-3.
Фрагмент Си-кода:
printf("Content-type: text/html; charset=windows-1251\n\n");
printf("<html>\n"
"<head>\n"
"<title>p_C_2</title>\n"
"</head>\n"
"<body>\n"
....
Здесь все литералы конкатенационно склеиваются, и получается один большой литерал. У меня это работает, но будет ли это работать на всех компьютерах? Существует ли правило, согласно которому последовательные литералы, не разделённые запятыми, склеиваются в один литерал?
"Компьютерах"? При чем здесь "компьютерах"?
Вопрос о том, будет ли это работать во всех компиляторах языка С. Да, будет. Это требование стандарта языка.
-- 15.01.2023, 11:36 --Вот так штука. Ваш вариант с функцией kod gcc бракует, а g++ не бракует. Вот так компилирует чисто:
g++ zprint.c -o zprint.cgi -Wall -Werror -O3
Потому что С++ и С - два разных языка программирования.
-- 15.01.2023, 11:41 --Исходный мой вариант, без дополнительных const, компилирует чисто.
Компилятор не может вычислить неконстантные выражения, ему приходится создавать скрытый код инициализации, выполняющийся до
main. Идеология языка C такого не позволяет, поэтому там такое не работает.
Это верно, но не совсем. "Идеология языка С" во многих случаях считает константными выражения, которые не являются константными в реальных окружениях, в реальных ОС. В частности, это относится к адресным константам, например адресам глобальных переменных в ОС семейства *nix. Эти адреса компилятору на стадии компиляции не известны. Такие адреса прописываются в программу "в последний момент" загрузчиком (а не скрытым кодом инициализации, выполняющимся до
main). При этом загрузчик может даже выполнять некую базовую арифметику перед прописыванием адреса.