Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Выдать из функции указатель на ее статическую переменную
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
ViKo
В функции преобразую строку в число, и хочу выдать указатель на это число, если оно получилось из строки, и NULL, если в строке галимотня.
Можно определить глобальную int32_t переменную, в которую преобразовывать строку, и выдавать указатель на нее. Не нравится, что переменная глобальная.
Могу ли создать статическую переменную внутри функции, и выдавать указатель на нее?
Mc_off
При вызове функции передавайте туда указатель на внешнюю переменную, в которую будете возвращать указатель на переменную внутри функции. Стандартный подход.
ViKo
Если переменная внутри функции не статическая, то после выхода из функции ее не станет, аннигилирует.
Мне незачем передавать указатель в функцию, если я знаю, указатель на что хочу выдать.
_pv
да можно конечно, только вот зачем?
использовать нулевой указатель в качестве индикатора ошибки что строка плохая? не надо так делать.

int * func(const char * str){
static int num = 0;
if (!str) return 0;
num = atoi(str);
return #
}
adnega
Цитата(ViKo @ Dec 5 2014, 14:39) *
Если переменная внутри функции не статическая, то после выхода из функции ее не станет, аннигилирует.
Мне незачем передавать указатель в функцию, если я знаю, указатель на что хочу выдать.

Либо передавать указатель в функцию, либо передавать результат в возвращаемом значении.
Глобальная переменная, а уж тем более локальная переменная (пусть даже и static) - неоправданно для такого функционала.
Вроде, есть стандартные функции для перевода строки в число. Чем они не устраивают?
ViKo
Цитата(_pv @ Dec 5 2014, 13:45) *
да можно конечно, только вот зачем?
использовать нулевой указатель в качестве индикатора ошибки что строка плохая? не надо так делать.

int * func(const char * str){
static int num = 0;
if (!str) return 0;
num = atoi(str);
return #
}

Да, именно, для индикации ошибки. А чем плохо? atoi при неправильной строке выдает неопределенное значение. Мне это не подходит. Свое преобразование буду делать.

Цитата(adnega @ Dec 5 2014, 13:48) *
Либо передавать указатель в функцию, либо передавать результат в возвращаемом значении.
Глобальная переменная, а уж тем более локальная переменная (пусть даже и static) - неоправданно для такого функционала.
Вроде, есть стандартные функции для перевода строки в число. Чем они не устраивают?

А что мне выдаст atoi("XPEN_TEBE!") ? rolleyes.gif И как я об этом узнаю? Можно bool OK выдать, но все равно ссылку на результат нужно (ну, да, глобальную переменную можно).
SM
Цитата(ViKo @ Dec 5 2014, 13:54) *
А что мне выдаст atoi("XPEN_TEBE!") ? rolleyes.gif И как я об этом узнаю?

Для этого более продвинутая strtol есть.

А вообще, в старые добрые времена, для этого глобальная переменная "errno" была. Чтобы за собой всякие коды ошибок сообщать. Чем такой подход не устроил? сделать my_errno
AlexandrY
Цитата(ViKo @ Dec 5 2014, 12:26) *
В функции преобразую строку в число, и хочу выдать указатель на это число, если оно получилось из строки, и NULL, если в строке галимотня.
Можно определить глобальную int32_t переменную, в которую преобразовывать строку, и выдавать указатель на нее. Не нравится, что переменная глобальная.
Могу ли создать статическую переменную внутри функции, и выдавать указатель на нее?


Я бы возвращал число, а не указатель.
А в аргументы бы добавил указатель на идентификатор ошибки.
Если указатель на идентификатор NULL, то ошибку не записывать.

Таким образом можно либо вообще игнорировать ошибки (чтобы быстрее писать код) либо делать в определенных случаях детализированный лог ошибок.
Неплохой вариант переменную ошибки сделать глобальной.

Смысл в том чтобы с рабочими переменными поменьше применять указатели, а все что касается отладочных ситуаций и ошибок переводить на указатели как менее критичный код.
CrimsonPig
Цитата(ViKo @ Dec 5 2014, 10:26) *
В функции преобразую строку в число, и хочу выдать указатель на это число, если оно получилось из строки, и NULL, если в строке галимотня.
Можно определить глобальную int32_t переменную, в которую преобразовывать строку, и выдавать указатель на нее. Не нравится, что переменная глобальная.
Могу ли создать статическую переменную внутри функции, и выдавать указатель на нее?


...чем только люди не страдают...
"Число-то" какого типа ?
Что мешает в общем виде сделать так ? предполагаем, что типа нашего числа int32

/**
@param pointer to a string to convert to a number
@param pointer to the variable that will be assigned the value on success
@return true if everything is OK
*/
bool MyAtoI(const char* apStr, int32* apRetVal)
{
[.. some dirty magic here..]
}
ViKo
Вижу, вариантов много. Но не вижу лучшего. rolleyes.gif
SM
Цитата(ViKo @ Dec 5 2014, 14:31) *
Вижу, вариантов много. Но не вижу лучшего. rolleyes.gif


Сделайте как в strtol - результат функции - само число. А указатель - на последний символ, на котором "запнулось" преобразование. По нему все сразу понятно. Если там isspace или ноль (конец строки), значит все ОК. Самая простая проверка - *endptr<=0x20 - под это попадает все сразу, все концы строк, ноль, пробел, табуляция.
CrimsonPig
Цитата(ViKo @ Dec 5 2014, 11:31) *
Вижу, вариантов много. Но не вижу лучшего. rolleyes.gif


А не соизволит ли многоуважаемый Дон четко определить критерии "лучшести" ?
с моей т.з. все что есть лучше того бреда из первого поста.
ViKo
Цитата(SM @ Dec 5 2014, 14:33) *
Сделайте как в strtol - результат функции - само число. А указатель - на последний символ, на котором "запнулось" преобразование. По нему все сразу понятно. Если там isspace или ноль (конец строки), значит все ОК. Самая простая проверка - *endptr<=0x20 - под это попадает все сразу, все концы строк, ноль, пробел, табуляция.

Функция сложновата, мне столько не нужно. Или в строке десятичное число со знаком или без, или "галимотня".
Указатель, ползущий по строке - сохраняется в глобальной переменной, для других парсерных функций. На этом числе еще не конец.
SM
Цитата(ViKo @ Dec 5 2014, 15:11) *
Функция сложновата, мне столько не нужно. Или в строке десятичное число со знаком или без, или "галимотня".
Указатель, ползущий по строке - сохраняется в глобальной переменной, для других парсерных функций. На этом числе еще не конец.


Так тогда strtol вам и нужна в чистом ее виде. Зачем глобальная переменная с ползущим указателем, когда она при использовании strtol становится локальная - strtol ее и возвращает, именно, чтобы распознать галиматью, конец строки, или продолжить со следующим числом, все зайцы убиты одним выстрелом и без глобальных переменных. В strtol передаем указатель на текущее положение в строке, и передаем в качестве указателя на конец указатель на этот же указатель sm.gif sm.gif sm.gif - в результате он один и "ползет по строке".

Или, сделайте так:

int my_strtol(char **pPtr);

То есть сразу передаете в функцию указатель на указатель, который передвигается по строке. По тому, на чем он остановился после вызова функции, распознаете, что там. Это эквивалентно вызову strtol(ptr, *ptr, 10).
AlexandrY
Цитата(SM @ Dec 5 2014, 14:18) *
Так тогда strtol вам и нужна в чистом ее виде. Зачем глобальная переменная с ползущим указателем, когда она при использовании strtol становится локальная - strtol ее и возвращает, именно, чтобы распознать галиматью, конец строки, или продолжить со следующим числом, все зайцы убиты одним выстрелом и без глобальных переменных. В strtol передаем указатель на текущее положение в строке, и передаем в качестве указателя на конец указатель на этот же указатель sm.gif sm.gif sm.gif - в результате он один и "ползет по строке".


strtol опасна в плане RTOS, функции этого ряда могут внутри себя лезть в глобальный heap и в глобальные переменные.
Её либо надо ретаргетить, либо не использовать, либо лепить вокруг них критические секции.

Но если до красоты, то на мой эстетский взгляд самое красивое все делать в глобальных структурах. Т.е. объединять глобальные переменные в глобальные структуры.
Пока задача одна структура глобальна, как только задач несколько структуру одним движением превращаем в динамически выделяемую и уводим в управляющую структуру задачи.
Структуры никогда не подведут.
ViKo
Цитата(SM @ Dec 5 2014, 15:18) *
Так тогда strtol вам и нужна в чистом ее виде...

У этой функции 3 параметра.
Указатель, ползущий по строке, у меня в глобальной структуре имеется, его передавать не нужно.
Если попалась строка "-300голов", то мне логично промотать его до space-символов, а не остановиться на "г".
Не буду нарушать созданную логику, сделаю, как хотел.
Правильно, указатель на локальную статическую переменную выдавать и использовать снаружи функции можно?
SM
Цитата(AlexandrY @ Dec 5 2014, 15:30) *
strtol опасна в плане RTOS, функции этого ряда могут внутри себя лезть в глобальный heap и в глобальные переменные.

Это с какого перепуга то? Только errno, но это классика.

CODE

_CODE_ACCESS long strtol(const char *st, char **endptr, int base)
{
register unsigned long result = 0;
register unsigned int uns_base;
register char cp;
register const char *fst = st;
int digits = 0;
unsigned long sign = 0;
unsigned long max_prev_result;
unsigned long max_curr_addval;
unsigned long range_limit;

while (_isspace(*fst)) ++fst; /* SKIP WHITE SPACE */

if ((cp = *fst) == '-')
{
sign = 1;
cp = *++fst;
}
else if (cp == '+') cp = *++fst;

if (base > 36) base = 0;

/*-------------------------------------------------------------------*/
/* DETERMINE BASE IF ZERO BASE ASKED FOR. */
/*-------------------------------------------------------------------*/
switch (base)
{
case 0 : if (cp != '0') base = 10;
else if ((cp = *++fst) == 'x' || cp == 'X')
if (_isxdigit(fst[1])) { base = 16; cp = *++fst; }
else { base = 10; cp = *--fst; }
else
{
base = 8;
if (cp < '0' || cp > '7') cp = *--fst;
}
break;

case 16 : if (cp == '0' && ((fst[1] == 'x') || (fst[1] == 'X')) &&
_isxdigit(fst[2]))
cp = *(fst += 2);
}

/*-------------------------------------------------------------------*/
/* DETERMINE VALUES NEEDED TO DETECT RANGE ERROR. THE MAX UNSIGNED */
/* VALUE THAT IS IN RANGE IS BASED ON THE SIGN OF THE INPUT STRING: */
/* sign == 1 - RESULT WILL BE NEGATIVE, SO MUST BE <= LONG_MAX+1 */
/* sign == 0 - RESULT WILL BE POSITIVE, SO MUST BE <= LONG_MAX */
/* SO range_limit is LONG_MAX + sign. */
/* */
/* ALSO NEED max_prev_result AND max_curr_addval WHERE: */
/* max_prev_result * uns_base + max_curr_addval == range_limit */
/* */
/* THIS ALLOWS US TO TEST FOR RANGE ERROR BEFORE WE COMPUTE THE NEXT */
/* RESULT. WE HAVE TWO CASES: */
/* - PREVIOUS result IS GREATER THAN max_prev_result, SO NEXT */
/* RESULT MUST BE OUT OF RANGE. */
/* - PREVIOUS result IS EQUAL TO max_prev_result, SO NEXT RESULT */
/* IS OUT OF RANGE IF addval > max_curr_addval. */
/*-------------------------------------------------------------------*/
uns_base = (unsigned int) base;
range_limit = (unsigned long)LONG_MAX + sign;
max_prev_result = range_limit / uns_base;
max_curr_addval = range_limit % uns_base;

/*-------------------------------------------------------------------*/
/* CONVERT THE NUMBER USING THE SPECIFIED BASE. */
/*-------------------------------------------------------------------*/
for (;; cp = *++fst)
{
register unsigned long addval;

if (!((_isdigit(cp) && (addval = cp - '0') < uns_base) ||
(_isupper(cp) && (addval = cp - 'A' + 10) < uns_base) ||
(_islower(cp) && (addval = cp - 'a' + 10) < uns_base))) break;

/*--------------------------------------------------------------*/
/* CHECK OVERFLOW STATUS BEFORE COMPUTATION. */
/* result CONTAINS THE RESULT OF THE PREVIOUS COMPUTATION */
/*--------------------------------------------------------------*/
if (result > max_prev_result ||
(result == max_prev_result && addval > max_curr_addval))
{
/* SET ERRNO */
errno = ERANGE;
if (endptr) *endptr = (char *)st;
return sign ? LONG_MIN : LONG_MAX;
}

/*--------------------------------------------------------------*/
/* COMPUTE NEXT RESULT. */
/*--------------------------------------------------------------*/
result = result * uns_base + addval;

digits++;
}

/*-------------------------------------------------------------------*/
/* MARK THE END OF THE CONVERTED INPUT. NEGATE THE RESULT IF A */
/* MINUS SIGN WAS SEEN. */
/*-------------------------------------------------------------------*/
if (endptr) *endptr = (char *)(digits ? fst : st);
if (sign)
return (long)-result;

return (long)result;
}
ViKo
Цитата(AlexandrY @ Dec 5 2014, 15:30) *
Но если до красоты, то на мой эстетский взгляд самое красивое все делать в глобальных структурах. Т.е. объединять глобальные переменные в глобальные структуры.

Делаю так. beer.gif Вот, запнулся на числе после atoi. Не гармонирует с остальными членами. rolleyes.gif
SM
Цитата(ViKo @ Dec 5 2014, 15:33) *
Правильно, указатель на локальную статическую переменную выдавать и использовать снаружи функции можно?

Теоретически, можно, но не нужно. Сделайте тогда статическую глобальную переменную, ее и видно никому не будет снаружи, и возвращать указатель на нее без проблем.
ViKo
Цитата(SM @ Dec 5 2014, 15:38) *
Теоретически, можно, но не нужно. Сделайте тогда статическую глобальную переменную, ее и видно никому не будет снаружи, и возвращать указатель на нее без проблем.

Ок! Спасибо.
SM
Цитата(ViKo @ Dec 5 2014, 15:40) *
Ок! Спасибо.

Только не забудьте, что если вдруг многопоточность... То кирдык. Надо будет крит. секцию ставить.
ViKo
Цитата(SM @ Dec 5 2014, 15:42) *
Только не забудьте, что если вдруг многопоточность... То кирдык. Надо будет крит. секцию ставить.

Запись в буфер и разбор с ответом идут по-очереди, типа пинг-понга. Над внеочередными событиями пока не задумывался, сделать бы хоть так. Разбор с ответом - один тред.
SM
Цитата(ViKo @ Dec 5 2014, 15:46) *
Разбор с ответом - один тред.

Это сейчас sm.gif А потом захотите в другом треде что-то сделать этой же ф-цией, и будете сильно удивлены странными глюками....
ViKo
Кстати, как это слово правильно использовать, переводить - thread. Перевод найти легко - "нить", но что именно использовать?

Цитата(SM @ Dec 5 2014, 15:48) *
Это сейчас sm.gif А потом захотите в другом треде что-то сделать этой же ф-цией, и будете сильно удивлены странными глюками....

Не захочу, она у меня с префиксом, однозначно определяющем принадлежность к данной задаче.
Переменную int32_t тоже впихну в одну из структур, принадлежащих задаче. sm.gif
SM
Цитата(ViKo @ Dec 5 2014, 15:51) *
Кстати, как это слово правильно использовать, переводить - thread. Перевод найти легко - "нить", но что именно использовать?

Поток, это по-нашему.
ViKo
Цитата(SM @ Dec 5 2014, 16:19) *
Поток, это по-нашему.

Со stream'ом вступает в конфликт. Ок, поток так поток. biggrin.gif
dxp
Возвращать результат из функции, храня его во внутреннем статическом объекте можно, но есть серьёзные недостатки:

1. Функция получается нереентерабельной.
2. Результат может быть не когерентен вызову даже в момент возврата из функции (опять же из-за возможности асинхронного вызова функции).
3. В случае возвращаемого целого обычный возврат по значению будет, скорее всего, эффективней.
4. Есть рабочий конкурент - strtol, про него уже сказали, ни разу не сложная функция, всяко проще, чем самому огороды городить. Не нравится она в таком виде, написать обёртку.
ViKo
Я же указатель возвращаю, не сам объект. И указатель может быть NULL, в случае ошибки. Мне так удобно.
Вы правы! Я уже с этим статиком накололся. Не сбросил число от предыдущей обработки, увеличил прошлое.
От "бреда" избавился. Работает глобальная переменная, как надо. Может, если статическую переменную каждый раз инициализировать при вызове функции, и сгодилось бы. Но красоты в этом я уже не вижу.
Сергей Борщ
Цитата(ViKo @ Dec 5 2014, 17:25) *
Работает глобальная переменная, как надо.
В чем ее отличие от статической внутри функции? Кроме того, что ее кто угодно поломать может и ему за это ничего не будет. Если функция возвращает указатель на свою статическую переменную как указатель на константу, то компилятор хоть по рукам даст при попытке эту переменную изменить извне.
Slash
Указатель на переменную успеха/неудачи передавать в качестве параметра.

Объявление:
Код
double toDouble(const char * str, bool * ok);


Применение:
Код
const char * str = "0.252";
bool ok;
double var = toDouble(str, &ok);
ViKo
Цитата(Сергей Борщ @ Dec 5 2014, 21:25) *
В чем ее отличие от статической внутри функции? Кроме того, что ее кто угодно поломать может и ему за это ничего не будет. Если функция возвращает указатель на свою статическую переменную как указатель на константу, то компилятор хоть по рукам даст при попытке эту переменную изменить извне.

Я по дурости работал внутри функции непосредственно со статической переменной. При входе в программу в следующий раз предыдущее содержимое переменной не стирал. Естественно, результат просто накапливался.
Нужно было работать с другой локальной (регистровой) переменной, а результат скидывать в статическую.
Пока ушел на внешнюю глобальную переменную. Она в своем файле хранится, так что не настолько уж и "глобальная" (правда, для этого статической ее нужно квалифицировать).
_Pasha
bool или нет, но
Код
unsigned char str2int32(int32_t *result, char *s); // returns 0 if error or  number of symbols handled
//....usage
int32_t a,b,c,d;
char source[]="123, 7689540";
char s2[]="123,7689540";

if(str2int32(&a,source)&&str2int32(&b,&source[5])
{
  c = a+b;
}

if(str2int32(&a,&s2[str2int32(&b,s2)]))
{
  d = a+b;
}

assert(c==d);

каждый д*чит как х*чет.
там есть момент, где игнорировать символы, слева или справа, но это уже религиозный sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.