|
Выдать из функции указатель на ее статическую переменную |
|
|
|
Dec 5 2014, 10:48
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(ViKo @ Dec 5 2014, 14:39)  Если переменная внутри функции не статическая, то после выхода из функции ее не станет, аннигилирует. Мне незачем передавать указатель в функцию, если я знаю, указатель на что хочу выдать. Либо передавать указатель в функцию, либо передавать результат в возвращаемом значении. Глобальная переменная, а уж тем более локальная переменная (пусть даже и static) - неоправданно для такого функционала. Вроде, есть стандартные функции для перевода строки в число. Чем они не устраивают?
|
|
|
|
|
Dec 5 2014, 10:54
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(_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!") ?  И как я об этом узнаю? Можно bool OK выдать, но все равно ссылку на результат нужно (ну, да, глобальную переменную можно).
|
|
|
|
|
Dec 5 2014, 11:19
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

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

Местный
  
Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502

|
Цитата(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..] }
Сообщение отредактировал CrimsonPig - Dec 5 2014, 11:20
|
|
|
|
|
Dec 5 2014, 11:33
|
Гуру
     
Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881

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

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(SM @ Dec 5 2014, 14:33)  Сделайте как в strtol - результат функции - само число. А указатель - на последний символ, на котором "запнулось" преобразование. По нему все сразу понятно. Если там isspace или ноль (конец строки), значит все ОК. Самая простая проверка - *endptr<=0x20 - под это попадает все сразу, все концы строк, ноль, пробел, табуляция. Функция сложновата, мне столько не нужно. Или в строке десятичное число со знаком или без, или "галимотня". Указатель, ползущий по строке - сохраняется в глобальной переменной, для других парсерных функций. На этом числе еще не конец.
|
|
|
|
|
Dec 5 2014, 12:18
|
Гуру
     
Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881

|
Цитата(ViKo @ Dec 5 2014, 15:11)  Функция сложновата, мне столько не нужно. Или в строке десятичное число со знаком или без, или "галимотня". Указатель, ползущий по строке - сохраняется в глобальной переменной, для других парсерных функций. На этом числе еще не конец. Так тогда strtol вам и нужна в чистом ее виде. Зачем глобальная переменная с ползущим указателем, когда она при использовании strtol становится локальная - strtol ее и возвращает, именно, чтобы распознать галиматью, конец строки, или продолжить со следующим числом, все зайцы убиты одним выстрелом и без глобальных переменных. В strtol передаем указатель на текущее положение в строке, и передаем в качестве указателя на конец указатель на этот же указатель  - в результате он один и "ползет по строке". Или, сделайте так: int my_strtol(char **pPtr); То есть сразу передаете в функцию указатель на указатель, который передвигается по строке. По тому, на чем он остановился после вызова функции, распознаете, что там. Это эквивалентно вызову strtol(ptr, *ptr, 10).
|
|
|
|
|
Dec 5 2014, 12:30
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(SM @ Dec 5 2014, 14:18)  Так тогда strtol вам и нужна в чистом ее виде. Зачем глобальная переменная с ползущим указателем, когда она при использовании strtol становится локальная - strtol ее и возвращает, именно, чтобы распознать галиматью, конец строки, или продолжить со следующим числом, все зайцы убиты одним выстрелом и без глобальных переменных. В strtol передаем указатель на текущее положение в строке, и передаем в качестве указателя на конец указатель на этот же указатель  - в результате он один и "ползет по строке". strtol опасна в плане RTOS, функции этого ряда могут внутри себя лезть в глобальный heap и в глобальные переменные. Её либо надо ретаргетить, либо не использовать, либо лепить вокруг них критические секции. Но если до красоты, то на мой эстетский взгляд самое красивое все делать в глобальных структурах. Т.е. объединять глобальные переменные в глобальные структуры. Пока задача одна структура глобальна, как только задач несколько структуру одним движением превращаем в динамически выделяемую и уводим в управляющую структуру задачи. Структуры никогда не подведут.
|
|
|
|
|
Dec 5 2014, 12:33
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(SM @ Dec 5 2014, 15:18)  Так тогда strtol вам и нужна в чистом ее виде... У этой функции 3 параметра. Указатель, ползущий по строке, у меня в глобальной структуре имеется, его передавать не нужно. Если попалась строка "-300голов", то мне логично промотать его до space-символов, а не остановиться на "г". Не буду нарушать созданную логику, сделаю, как хотел. Правильно, указатель на локальную статическую переменную выдавать и использовать снаружи функции можно?
|
|
|
|
|
Dec 5 2014, 12:34
|
Гуру
     
Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881

|
Цитата(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; }
|
|
|
|
|
Dec 5 2014, 15:23
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Возвращать результат из функции, храня его во внутреннем статическом объекте можно, но есть серьёзные недостатки:
1. Функция получается нереентерабельной. 2. Результат может быть не когерентен вызову даже в момент возврата из функции (опять же из-за возможности асинхронного вызова функции). 3. В случае возвращаемого целого обычный возврат по значению будет, скорее всего, эффективней. 4. Есть рабочий конкурент - strtol, про него уже сказали, ни разу не сложная функция, всяко проще, чем самому огороды городить. Не нравится она в таком виде, написать обёртку.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Dec 5 2014, 19:16
|
Местный
  
Группа: Участник
Сообщений: 202
Регистрация: 10-04-05
Из: Санкт-Петербург
Пользователь №: 4 011

|
Указатель на переменную успеха/неудачи передавать в качестве параметра. Объявление: Код double toDouble(const char * str, bool * ok); Применение: Код const char * str = "0.252"; bool ok; double var = toDouble(str, &ok);
|
|
|
|
|
Dec 6 2014, 16:08
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
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); каждый д*чит как х*чет. там есть момент, где игнорировать символы, слева или справа, но это уже религиозный
Сообщение отредактировал _Pasha - Dec 6 2014, 16:10
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|