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 (даже если пока он "вроде бы работает").
C>Я где-то увидел такое решение, и чуть не припух. Ибо проект был солидный, и парни там грамотные. Очень долго въезжал, что к чему. Потом стало ясно.
Похоже не до конца въехал
приведенный код не работает, портит строку.
http://ideone.com/zwSsUP
Здравствуйте, 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); // которые сделаны специально совместимыми для использования в сишных функциях
}
Здравствуйте, Кодт, Вы писали:
К>К>// хорошо №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
несмотря на поддержку в конкретном компиляторе, возникает соблазн использовать такое повсюду (писать свои такие же классы, затем писать так в гцц и тд)
в целом, плохая практика имхо
А зачем все так сложно с этой переменной 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-ух строчках, а не размазаны по коду ниже…