PDA

Просмотр полной версии : [Вопрос] Можно ли создать public-функции с ограниченной областью (static) видимости?



Geebrox
22.05.2018, 11:43
Как я знаю, можно ограничить область видимости обычных функций с помощью "static". Можно ли как нибудь ограничить область видимости колбеков, чтобы они были доступны только в одном файле?
У меня получилось ограничить таким способом:



static @SomeFunc();
static @SomeFunc() { }


Но это не совсем то, что я хочу. То есть этот метод функционирует не так как обычные функции с ограниченной областью видимости. Конечно в этом случае тоже нельзя вызывать функцию из другого файла, но и нельзя создать функцию с анологичным называнием.

Есть идеи? Можно ли как нибудь это реализовать?

DeimoS
22.05.2018, 12:17
Эмм, ты создаёшь публичные (общедоступные) функции и хочешь ограничить их зону видимости? :crazy: Не находишь противоречия в своих словах?

Geebrox
22.05.2018, 14:30
Эмм, ты создаёшь публичные (общедоступные) функции и хочешь ограничить их зону видимости? :crazy: Не находишь противоречия в своих словах?

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

ziggi
22.05.2018, 15:34
Паблик функции на то и паблик, что их область видимости нельзя ограничить не только для одного файла, но даже для одного скрипта.

Geebrox
22.05.2018, 16:39
Паблик функции на то и паблик, что их область видимости нельзя ограничить не только для одного файла, но даже для одного скрипта.

Ну я это понимаю. Но я объяснил, что мне нужно. Обычным функциям нельзя обращаться через название при вызове (компилятор генерирует адрес для них, как я понимаю). А паблик функциям можно обращаться через название (т.к. компилятор делает это возможным) насчёт чего их можно вызывать с помощью таких функций как Call(Local/Remote)Function | SetTimer(Ex) | mysql_(t/p)query | и т. д. и т. п.

Короче говоря, нельзя реализовать то, что я хочу?

- - - Добавлено - - -

Я уточнил, оказывается это не возможно, можно закрывать тему.

VVWVV
22.05.2018, 16:49
Теоретически можно и обычную функцию с помощью таймера вызвать, но нужно ли это? Чтобы уменьшить вероятность совпадения названий функций - делайте их как можно больше.

Daniel_Cortez
22.05.2018, 16:59
Конечно в этом случае тоже нельзя вызывать функцию из другого файла, но и нельзя создать функцию с анологичным называнием.
Только что проверил - оказывается, можно.

myinc.inc

static @SomeFunc();
static @SomeFunc()
{
emit const.pri 0;
}

main.p:

#include "myinc.inc"

@SomeFunc();
@SomeFunc()
{
emit const.pri 1;
}

main()
{
@SomeFunc();
}

Вывод pawndisasm:

00000000 halt 00000000

00000008 proc ; @SomeFunc
0000000c const.pri 00000000
00000014 zero.pri
00000018 retn

0000001c proc ; @SomeFunc
00000020 const.pri 00000001
00000028 zero.pri
0000002c retn

00000030 proc
00000034 push.c 00000000
0000003c call 0000001c ; @SomeFunc
00000044 zero.pri
00000048 retn

Как видно из листинга, создаются две public-функции с одинаковым именем. В таблице экспортируемых (public-) функций название "@SomeFunc" тоже дублируется. Нужно будет сообщить об этом баге...

Также интересно, что CallLocalFunction перед вызовом отыскивает нужную функцию по названию в таблице public-функций, причём использует не линейный, а бинарный поиск. Это означает, что из двух и более функций с одинаковым названием CallLocalFunction может вызвать любую из них. Например, сейчас она может вызывать вторую, а добавь или удали какую-нибудь ещё public-функцию, и вызываться будет первая.

DeimoS
22.05.2018, 16:59
Ну смотри: ты хочешь в разных файлах создавать паблики с одинаковыми именами. Далее представим, что ты решил вызвать один из пабликов при помощи CallRemoteFunction: каким образом сервер поймёт к какому именно ты обращаешься паблику?

Чтоб такое реализовать, нужно, как я понимаю, модифицировать процесс регистрации паблик функций, добавляя отдельную "таблицу" со static пабликами. И уже для обращения к этим пабликам делать отдельные функции, которые уже не смогут обращаться к каким-то пабликам за пределами файла. Ну и решить ещё ряд подводных камней. В итоге, ты получишь обрубок обычных функций и не более того.

Как вариант, можешь попробовать использовать автоматоны. Но в данном случае это будет больше как извращение, чем полезная фича

Geebrox
22.05.2018, 17:12
А можно ли обычную функцию вызвать через адрес? И как узнать адрес функций?

Nexius_Tailer
22.05.2018, 17:14
Так а если сделать что-то вроде обёртки для конкретных функций, в которой будет объявляться паблик с таким же именем и из него будет вызываться эта функция? Вполне как вариант, если таких конкретных функций не очень много (т.к. объявлять каждую из них надо будет через этот дефайн-обёртку). Единственная проблема это область видимости, коя хоть и будет на все файлы и скрипты, но в большинстве случаев это не так критично (особенно если делаешь просто для себя).

Geebrox
22.05.2018, 17:29
особенно если делаешь просто для себя.

Ну и проблема то в том, что не для себя. Если бы для себя, зачем себя ограничивать от вызова функций или название такой же функций (я же буду знать, что можно | что нельзя)

Мне нужно ограничить вызов функций, которая находится в конкретном файле. Но в этом самом файле идет обращение к этой функции через название, что делает не возможным создать её как обычную и ограничить зону через static.

VVWVV
22.05.2018, 17:47
Только что проверил - оказывается, можно.

myinc.inc

static @SomeFunc();
static @SomeFunc()
{
emit const.pri 0;
}

main.p:

#include "myinc.inc"

@SomeFunc();
@SomeFunc()
{
emit const.pri 1;
}

main()
{
@SomeFunc();
}

Вывод pawndisasm:

00000000 halt 00000000

00000008 proc ; @SomeFunc
0000000c const.pri 00000000
00000014 zero.pri
00000018 retn

0000001c proc ; @SomeFunc
00000020 const.pri 00000001
00000028 zero.pri
0000002c retn

00000030 proc
00000034 push.c 00000000
0000003c call 0000001c ; @SomeFunc
00000044 zero.pri
00000048 retn

Как видно из листинга, создаются две public-функции с одинаковым именем. В таблице экспортируемых (public-) функций название "@SomeFunc" тоже дублируется. Нужно будет сообщить об этом баге...

Также интересно, что CallLocalFunction перед вызовом отыскивает нужную функцию по названию в таблице public-функций, причём использует не линейный, а бинарный поиск. Это означает, что из двух и более функций с одинаковым названием CallLocalFunction может вызвать любую из них. Например, сейчас она может вызывать вторую, а добавь или удали какую-нибудь ещё public-функцию, и вызываться будет первая.

Хм, странно, что не работает проверка на совпадение одинаковых названий.

Geebrox
22.05.2018, 18:13
Y_Less утверждает, что вызывается та функция которая находится в области видимости:



Сообщение от Y_Less:
That seems pretty clear and correct to me. It calls the one visible in the current scope (0000001c in the assembly).



https://i.imgur.com/Y73OxRP.jpg

DeimoS
22.05.2018, 18:29
Мне нужно ограничить вызов функций, которая находится в конкретном файле. Но в этом самом файле идет обращение к этой функции через название, что делает не возможным создать её как обычную и ограничить зону через static.

В смысле? Если тебе не нужно вызывать функцию через таймер, то и публичной её делать не обязательно, раз тебе нужно вызывать её только внутри файла.

Опиши подробнее что именно ты хочешь сделать.

Geebrox
22.05.2018, 18:34
Если тебе не нужно вызывать функцию через таймер, то и публичной её делать не обязательно, раз тебе нужно вызывать её только внутри файла.

Эммм, я вроде сказал, что нужно вызывать через таймер, только внутри файла. В первом посту (вроде)

DeimoS
22.05.2018, 18:39
Эммм, я вроде сказал, что нужно вызывать через таймер, только внутри файла. В первом посту (вроде)

А в чём проблема сделать уникальное имя? :scratch_one-s_head: По-моему, ты опять пытаешься создать проблему на ровном месте :)

Это ведь, как уже выяснилось, ни только не реализуемо, так ещё и понимание кода поломает, ибо даже если бы была возможность создать функцию таймера с ограниченной зоной видимости, этим никто в SA-MP не пользовался до тебя, поэтому люди, при виде одинаковых функций и куче одинаковых таймеров, будут не понимать что происходит в твоём коде.

Geebrox
22.05.2018, 18:46
А в чём проблема сделать уникальное имя? :scratch_one-s_head: По-моему, ты опять пытаешься создать проблему на ровном месте :)

ибо даже если бы была возможность создать функцию таймера с ограниченной зоной видимости, этим никто в SA-MP не пользовался до тебя.

Мне просто инетересно. Есть много путей выхода из данной ситауции, но я хочу попробовать именно такую (если возможно).
Велосипедом тоже не пользовались пока его не придумали.

Daniel_Cortez
22.05.2018, 19:41
А можно ли обычную функцию вызвать через адрес? И как узнать адрес функций?

emit const.pri SomeFunc;
emit push.c 0;
emit call.pri;
emit stack ((cellbits / charbits) * 1);

Как-то так. Доступно в последних версиях компилятора.


Y_Less утверждает, что вызывается та функция которая находится в области видимости:
Ну вот кто просил? Наверняка вопрос поставил неверно и тебя не так поняли.
Дай хоть ссылку, что ли, попробую объяснить там, в чём именно проблема (хоть теперь это и может оказаться сложнее).

VVWVV
22.05.2018, 19:50
emit const.pri SomeFunc;
emit push.c 0;
emit call.pri;
emit stack ((cellbits / charbits) * 1);

Как-то так. Доступно в последних версиях компилятора.


Кстати, данный код можно ещё использовать в макросах.

Видимо, проблема была решена http://forum.sa-mp.com/showthread.php?t=654148

Geebrox
22.05.2018, 20:04
emit const.pri SomeFunc;
emit push.c 0;
emit call.pri;
emit stack ((cellbits / charbits) * 1);

Как-то так. Доступно в последних версиях компилятора.


Ну вот кто просил? Наверняка вопрос поставил неверно и тебя не так поняли.
Дай хоть ссылку, что ли, попробую объяснить там, в чём именно проблема (хоть теперь это и может оказаться сложнее).

http://forum.sa-mp.com/showthread.php?p=4022174#post4022174

Он был прав, вызывается тот который находится в зоне видимости

Daniel_Cortez
23.05.2018, 16:53
Сообщил (https://github.com/pawn-lang/compiler/issues/306) о баге на GitHub.
Предлагаемые способы исправления:
Если функция объявлена со спецификатором static и её название начинается с "@", проверить, если функции с таким же названием в других областях видимости, если есть - выдать ошибку.
Запретить объявлять функции со спецификатором static, если имя функции начинается с "@" (компилятор уже считает неправильной комбинацию из "public" и "static").

ИМХО, второй вариант наиболее логичный, но всё же есть смысл быть готовым к любому исходу.