PDA

Просмотр полной версии : [Вопрос] Записать переменную в массив (enum)



Leogin
11.12.2022, 03:19
Здраствуйте. Подскажите как решить проблему, допусти есть массив:

enum e_Name {
Nick[MAX_PLAYER_NAME + 1],
Level,
};

new
Name[4][e_Name] = {
{"бета тест", 18},
{"тест", 8},
{"бета тест", 3},
{"бета тест", 1}
};


Хочу сделать так:

new
BETATEST1[] = "бета тест",
TEST1[] = "тест";

enum e_Name {
Nick[MAX_PLAYER_NAME + 1],
Level,
};

new
Name[4][e_Name] = {
{BETATEST1, 18}, // error 008: must be a constant expression; assumed zero
{TEST1, 8},
{BETATEST1, 3},
{BETATEST1, 1}
}; // error 010: invalid function or declaration
warning 203: symbol is never used: ""

punkochel
11.12.2022, 11:03
Дело в том, что в инициализации переменных/массива переменных значениями для них могут служить исключительно константы.
В твоем случае необходимо использовать функции strmid/strcat/format.

Я конечно не особо разбирался как работает компилятор pawn, но даже если объявить переменную с параметром const, то использование её в инициализации так-же не предоставляется возможным. Поэтому константы лучше объявлять директивой #define, если они будут использоваться при инициализации. То есть в pawn, на сколько мне известно, константы времени компиляции можно объявить только препроцессорной директивой.
Тут получается что никакого линкера и в помине нет, и компилирование проходит в 2 этапа: 1 - подставляются все значения директив препроцессора; 2 - непосредственно само компилирование.
Исходя из всего этого, когда ты инициализируешь массив используя значение объявленной переменной, то компилятор попросту не знает ничего о переменных BETATEST1, TEST1.

Daniel_Cortez
11.12.2022, 13:45
Дело в том, что в инициализации переменных/массива переменных значениями для них могут служить исключительно константы.
Не совсем, одиночные переменные можно инициализировать какими угодно значениями (из других переменных, от вызова функций и пр.) непосредственно при объявлении:

Return1() return 1;
main()
{
new x = Return1();
new y = x;
return y;
}

Ограничение касается именно массивов: их можно проинициализировать только строковыми или массивными литералами.
(На всякий случай разъясню, что такое "литерал" - это непосредственное константное значение: например, 0x0 - это целочисленный литерал, "текст" - это строковый литерал, { 0, 1, 2 } - это массивный литерал. Для сравнения, более часто используемое слово "константа" может означать как константное значение (например, 0xFF), так и именованную константу (например, const EOF = -1).)


Исходя из всего этого, когда ты инициализируешь массив используя значение объявленной переменной, то компилятор попросту не знает ничего о переменных BETATEST1, TEST1.
Знать-то он о них знает, только сделать с ними ничего не может: инициализация массивов содержимым других массивов непосредственно во время объявления не поддерживается (по крайней мере, пока что).

punkochel
11.12.2022, 14:16
Не совсем, одиночные переменные можно инициализировать какими угодно значениями (из других переменных, от вызова функций и пр.) непосредственно при объявлении:

Return1() return 1;
main()
{
new x = Return1();
new y = x;
return y;
}


Ну с локальными переменными это другая история, т.к. они создаются при входе в блок.
Но если мы будем говорить о локальном массиве, то мы не сможем даже указать его размер значением функции, которая возвращает константу:
Return5() return 5;
main()
{
new arr[Return1()];
}
Хотя, вроде бы что тут такого? Компилятору заранее известно значение которое вернет функция. Тем не менее это ошибка. Пусть у нас нет динамической памяти и функции возвращающие вычисленное значение не имеют места быть в инициализации, т.к. заранее стек расчитать невозможно.



Ограничение касается именно массивов: их можно проинициализировать только строковыми или массивными литералами.
{ 0, 1, 2 } - это массивный литерал
И тут мы увидим тоже ошибку:
stock Return5() return 5;
main()
{
new arr[] = {Return5(), Return5()};
}

Daniel_Cortez
18.12.2022, 18:04
Но если мы будем говорить о локальном массиве, то мы не сможем даже указать его размер значением функции, которая возвращает константу:

Return5() return 5;
main()
{
new arr[Return1()];
}
Хотя, вроде бы что тут такого? Компилятору заранее известно значение которое вернет функция.
Нет, не известно. В отличие от современных компиляторов для Си-подобных языков, компилятор Pawn не работает с абстрактным синтаксическим древом (Abstract Syntax Tree, AST (https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE)), поэтому многие трансформации и оптимизации кода для него невозможны. Он просто преобразует исходный код, который ему подан, напрямую в ассемблерный листинг, а затем и в байт-код. К слову, те же диагностики warning 240 и warning 252 были бы гораздо проще в реализации при использовании AST; без этого пришлось сильно костылить с запоминанием использования каждой переменной на каждом уровне вложенности if/switch/while/do/for/local.


И тут мы увидим тоже ошибку:

stock Return5() return 5;
main()
{
new arr[] = {Return5(), Return5()};
}


Ну так это же не константное значение, а результат функции, которая помимо возврата результата может совершать другие действия и иметь побочные эффекты (даже если в примере их нет, опять же, компилятор об этом не знает). Чего ещё здесь можно было ожидать?