Re[2]: return char*
От: N. I.  
Дата: 11.03.17 20:22
Оценка: +4
Carc:

J>>как вернуть значение локальной переменной szTmp?

C>
C>return &szTmp[0];
C>

C>Ибо, раз два плюса — то по умолчанию соглашение вызовов cdecl, то бишь освобождает стек вызывающая функция.
C>Соответственно, где-то в вызывающей функции строка вида будет валидна
C>
C>const char* const pszResult=…Sum();
C>

C>Т.к. после const char* const pszResult=… сам массив szTmp в вызываемой функции все еще будет существовать. В том смысле, что вызываемая уже отработала конечно, но вот добро ее на стеке все еще в полном порядочке лежит.

Это только один из возможных сценариев. Если компилятор начнёт оптимизировать код, результат может получиться совсем другим. Например, вызовы strcpy и strcat внутри Sum могут быть выброшены оптимизатором за ненадобностью, т.к. в этой функции изменённый массив szTmp нигде больше не используется, а за её пределами обращение к уничтоженному объекту уже незаконно (оптимизатору нет никакого дела до хаков, вызывающих undefined behavior, его задача действовать в рамках "as-if" rule, и выбрасывание strcpy вместе с strcat оное правило никак не нарушает). Встраивание самой Sum в код вызывающей функции тоже может привести к интересным результатам.

C>Я где-то увидел такое решение, и чуть не припух. Ибо проект был солидный, и парни там грамотные. Очень долго въезжал, что к чему. Потом стало ясно.

C>В общем, такие решения использовать можно.

В программе, которая должна работать надёжно, однозначно нельзя. При обнаружении такого кода его надо фиксить ASAP (даже если пока он "вроде бы работает").
Отредактировано 11.03.2017 20:31 N. I. . Предыдущая версия .
Re[7]: return char*
От: std.denis Россия  
Дата: 11.03.17 20:23
Оценка: +1
Pzz>Сразу видно, что ты никогда не программировал в среде, которая использует твой текущий стек для обработки прерываний.

да там и без прерываний хвост массива вполне потрётся при вызове конструктора и привет – возможный выбег за границу буфера
Re[8]: return char*
От: std.denis Россия  
Дата: 11.03.17 20:36
Оценка: 1 (1)
C>Я где-то увидел такое решение, и чуть не припух. Ибо проект был солидный, и парни там грамотные. Очень долго въезжал, что к чему. Потом стало ясно.

Похоже не до конца въехал приведенный код не работает, портит строку.
http://ideone.com/zwSsUP
Re[3]: return char*
От: Кодт Россия  
Дата: 13.03.17 10:43
Оценка:
Здравствуйте, Jumangee, Вы писали:

J>Вариант 1 — все работает! Благодарю!

J>Получить значение нужно всего 1 раз, т.к. следующего раза, возможно, уже не будет, а держать лишнюю переменную под промежуточное значение нет желания.

На всякий случай: главное, чтобы не накосячить по месту использования.

// было
char* Sum(); // проблемы, как вернуть строку...
void Work() {
  char* s = Sum();
  . . .
  printf("%s", s);
}

// плохо №1
std::string Sum();
void Work() {
  char* s = Sum().data();  // чтобы ниже переписывать по-минимуму
  // прямо с этого места s невалидно!
  . . .
  printf("%s", s);
}

// плохо №2
std::string Sum();
void Work() {
  std::string s = Sum();  // что получили, то и запомнили, хорошо
  . . .
  printf("%s", s); // передали в printf мусор (объект string устроен иначе, чем голый указатель)
}

// хорошо №1
std::string Sum();
void Work() {
  std::string s = Sum();
  . . .
  printf("%s", s.c_str()); // извлекли указатель правильным способом
}

// хорошо №2
CStringA Sum();  // у ATL/MFC есть свои классы строк
void Work() {
  CStringA s = Sum();
  . . .
  printf("%s", s); // которые сделаны специально совместимыми для использования в сишных функциях
}
Перекуём баги на фичи!
Re[4]: return char*
От: uzhas Ниоткуда  
Дата: 13.03.17 11:20
Оценка:
Здравствуйте, Кодт, Вы писали:

К>
К>// хорошо №2
К>CStringA Sum();  // у ATL/MFC есть свои классы строк
К>void Work() {
К>  CStringA s = Sum();
К>  . . .
К>  printf("%s", s); // которые сделаны специально совместимыми для использования в сишных функциях
К>}
К>


не так хорошо, как в №1 =\
http://stackoverflow.com/questions/14432539/c-passing-classes-to-vararg-function

несмотря на поддержку в конкретном компиляторе, возникает соблазн использовать такое повсюду (писать свои такие же классы, затем писать так в гцц и тд)
в целом, плохая практика имхо
Re[4]: return char*
От: Carc Россия https://vk.com/gosha_mazov
Дата: 13.03.17 11:39
Оценка: 70 (1)
А зачем все так сложно с этой переменной s, только чтобы не переписывать использование?

БЫЛО
К>// плохо №1
К>std::string Sum();
К>void Work() {
К>  char* s = Sum().data();  // чтобы ниже переписывать по-минимуму
К>  // прямо с этого места s невалидно!
К>  . . .
К>  printf("%s", s);
К>}


А нужно только поменять имя переменной получающей результат Sum(), и тут же строкой ниже привести ее char* s= в зависимости от типа переменной, в которой результат Sum()

// может и не хорошо, но уже неплохо
std::string Sum();
void Work() {
  std::string TEMP_VAR = Sum().data();  // чтобы ниже переписывать по-минимуму
  //а вот тут уже 
  char* s=TEMP_VAR.c_str();//приводим ее к нужному нам имени и нужным способом, в том же случае с CString просто переписываем эту строку на "char* s=(LPCTSTR)TEMP_VAR";
  // и вот прямо с этого места нам больше вообще ничего трогать и не потребуется…
  . . .
  printf("%s", s);


Не проще ли?
Изменения все равно понадобятся, в зависимости что у нас используется char* s, std::string, MFC|WTL::CString
Но по крайней мере изменения будут минимальны, а главное локализованы в одном месте — буквально в 2-ух строчках, а не размазаны по коду ниже…
Aml Pages Home
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.