Если заменить первый strcat на strcpy, то и обнуление *dst будет не нужно.
И если писать свою функцию, то можно и об эффективности позаботиться, поскольку неизвестно заранее, не будет ли она когда-либо использована в ситуации, где будет важна максимальная скорость. Я имею ввиду то, что у тебя второй strcat пробегает строку с самого начала в поисках нуля.
И последнее (спорное): Я бы вернул указатель на конец строки, поскольку указатель на начало у вызывающего уже есть.
Здравствуйте, igna, Вы писали:
I>Да, но к сожалению, если в этом месте будет ошибка вроде:
I>
I>sprintf("%s%s", s1, s2, s3);
I>
I>, то немаловероятно, что компилятор ее не заметит.
Как ни прискорбно это признавать С++ программисту, но семейство С printf функций с практической точки зрения является типобезопасным. Фактически не менее типобезопасно, чем С++ streams.
И gcc, и Intel C++, и Comeau умеют проверять количество и типы аргументов, передаваемых в printf функции. Так же это умеет проверять семейство провершиков Lint (Lint, LCLint, PC-lint, Flexelint). MSVC++ умеет только выборочно проверять типы, хотя не удивлюсь, есть MSVC2008 Team Edition уже умеет это делать в полном объёме.
Ну, что-то типа этого, только искал стандартное, а не самописное.
Вариант Bell вполне устроил.
Кстати, в предложенном тобой коде мне не нравится то, что память
вызывается в функции, а освобождается в нее ее. То есть, тот, кто
использует функцию может даже не знать, что он что-то обязан освободить.
Здравствуйте, DemAS, Вы писали:
DAS>Кстати, в предложенном тобой коде мне не нравится то, что память DAS>вызывается в функции, а освобождается в нее ее. То есть, тот, кто DAS>использует функцию может даже не знать, что он что-то обязан освободить.
Здравствуйте, DemAS, Вы писали:
DAS>Ну, что-то типа этого, только искал стандартное, а не самописное. DAS>Вариант Bell вполне устроил.
sprintf более универсальная функция, чем этого требует твоя задача.
DAS>Кстати, в предложенном тобой коде мне не нравится то, что память DAS>вызывается в функции, а освобождается в нее ее. То есть, тот, кто DAS>использует функцию может даже не знать, что он что-то обязан освободить.
Здравствуйте, DemAS, Вы писали:
DAS>Ну, что-то типа этого, только искал стандартное, а не самописное.
Судя по всему, стандартной функции нет DAS>Вариант Bell вполне устроил.
Проверь на производительность, если это критично. ИМХО вариант с memcpy должен быть быстрее.
DAS>Кстати, в предложенном тобой коде мне не нравится то, что память DAS>вызывается в функции, а освобождается в нее ее. То есть, тот, кто DAS>использует функцию может даже не знать, что он что-то обязан освободить.
Ну это вопрос докуменитрования — strdup тоже выделяет память, которую должен освободить пользователь.
Так что можно просто переименовать concat в concat_and_dont_forget2free_result
Да, но к сожалению, если в этом месте будет ошибка вроде:
sprintf("%s%s", s1, s2, s3);
, то немаловероятно, что компилятор ее не заметит.
Это замечание относится ко всем функциям со строкой форматирования, потому может быть не стоит использовать их там, где можно обойтись функциями из <string.h>.
Здравствуйте, igna, Вы писали:
I>Это замечание относится ко всем функциям со строкой форматирования, потому может быть не стоит использовать их там, где можно обойтись функциями из <string.h>.
У меня решение было такое же как у Bell, но перегрузил Janus, а ответ уже дали... )
в добавок sprintf СЕРЬЕЗНО тормознее остальных решений...
Здравствуйте, Plague, Вы писали:
P>Здравствуйте, igna, Вы писали:
I>>Это замечание относится ко всем функциям со строкой форматирования, потому может быть не стоит использовать их там, где можно обойтись функциями из <string.h>.
P>У меня решение было такое же как у Bell, но перегрузил Janus, а ответ уже дали... )
Ну уж извиняйте
P>в добавок sprintf СЕРЬЕЗНО тормознее остальных решений...
Я в этом тоже признался
I>Если заменить первый strcat на strcpy, то и обнуление *dst будет не нужно.
I>И если писать свою функцию, то можно и об эффективности позаботиться, поскольку неизвестно заранее, не будет ли она когда-либо использована в ситуации, где будет важна максимальная скорость. Я имею ввиду то, что у тебя второй strcat пробегает строку с самого начала в поисках нуля.
I>И последнее (спорное): Я бы вернул указатель на конец строки, поскольку указатель на начало у вызывающего уже есть.
Все подобные функции возвращают dst.
Здравствуйте, Sharp Eye, Вы писали:
SE>Здравствуйте, DemAS, Вы писали:
DAS>>Ну, что-то типа этого, только искал стандартное, а не самописное. DAS>>Вариант Bell вполне устроил.
SE>sprintf более универсальная функция, чем этого требует твоя задача.
DAS>>Кстати, в предложенном тобой коде мне не нравится то, что память DAS>>вызывается в функции, а освобождается в нее ее. То есть, тот, кто DAS>>использует функцию может даже не знать, что он что-то обязан освободить.
SE>Ну да, есть немного. Пардон, исправляюсь:
Здравствуйте, Roman Odaisky, Вы писали:
RO>3. strcat — любимая функция маляра Шлемиэля.
Забавно, что конец новой строки в strcat скорее всего есть и возвращать его не составило бы никакого труда.
Но! Эта возможность принесена в жертву возможности такой записи:
Здравствуйте, remark, Вы писали:
R>Забавно, что конец новой строки в strcat скорее всего есть и возвращать его не составило бы никакого труда.
Для этого на некоторых системах есть stpcpy, которая заменяет и strcpy, и strcat.
R>Но! Эта возможность принесена в жертву возможности такой записи: R>
Здравствуйте, remark, Вы писали:
R>Как ни прискорбно это признавать С++ программисту, но семейство С printf функций с практической точки зрения является типобезопасным. Фактически не менее типобезопасно, чем С++ streams. R>И gcc, и Intel C++, и Comeau умеют проверять количество и типы аргументов, передаваемых в printf функции. Так же это умеет проверять семейство провершиков Lint (Lint, LCLint, PC-lint, Flexelint). MSVC++ умеет только выборочно проверять типы, хотя не удивлюсь, есть MSVC2008 Team Edition уже умеет это делать в полном объёме.
А теперь строка форматирования приезжает из ресурсов. А теперь нужно вывести, например, boost::math::quaternion.
Здравствуйте, dmitry_npi, Вы писали:
_>Думаю, что заметит. Он скажет "Cannot convert from 'const char*' to 'char*'"
"%s%s" имеет тип array of 5 const char, но неявно приводится не только к pointer to const char, но и к pointer to char:
4.2 Array-to-pointer conversion
. . .
2 A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to
char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case,
the result is a pointer to the first element of the array. This conversion is considered only when there is an
explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an
rvalue. [Note: this conversion is deprecated. See Annex D. ] For the purpose of ranking in overload resolution
(13.3.3.1.1), this conversion is considered an array-to-pointer conversion followed by a qualification
conversion (4.4). [Example: "abc" is converted to “pointer to const char” as an array-to-pointer conversion,
and then to “pointer to char” as a qualification conversion. ]
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, remark, Вы писали:
R>>Как ни прискорбно это признавать С++ программисту, но семейство С printf функций с практической точки зрения является типобезопасным. Фактически не менее типобезопасно, чем С++ streams. R>>И gcc, и Intel C++, и Comeau умеют проверять количество и типы аргументов, передаваемых в printf функции. Так же это умеет проверять семейство провершиков Lint (Lint, LCLint, PC-lint, Flexelint). MSVC++ умеет только выборочно проверять типы, хотя не удивлюсь, есть MSVC2008 Team Edition уже умеет это делать в полном объёме.
RO>А теперь строка форматирования приезжает из ресурсов.
Если строка откуда-то приезжает, то частично это можно победить:
Здравствуйте, igna, Вы писали:
I>Здравствуйте, remark, Вы писали:
R>>И gcc, и Intel C++, и Comeau умеют проверять количество и типы аргументов, передаваемых в printf функции.
I>Comeau C/C++ 4.3.9 Online C99 : Compile succeeded и никаких warnings.
Да... действительно... он только printf проверяет.
Но хорошая новость относительно статической проверки программы заключается в том, что достаточно, что бы хотя бы один компилятор отлавливал каждый тип ошибки. С этой целью полезно поднять сборку проекта на сервере автосборки под cygwin/mingw, даже если вся работа ведётся под msvc++.
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, remark, Вы писали:
R>>Забавно, что конец новой строки в strcat скорее всего есть и возвращать его не составило бы никакого труда.
RO>Для этого на некоторых системах есть stpcpy, которая заменяет и strcpy, и strcat.
R>>Но! Эта возможность принесена в жертву возможности такой записи: R>>
Здравствуйте, remark, Вы писали:
RO>>А теперь нужно вывести, например, boost::math::quaternion. R>Я думаю, что все компиляторы должны ругаться на попытку передать пользовательский объект в ellipsis...
Я к тому, что в printf его вообще нельзя нормально вывести, а в std::ostream легко.
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, remark, Вы писали:
RO>>>А теперь нужно вывести, например, boost::math::quaternion. R>>Я думаю, что все компиляторы должны ругаться на попытку передать пользовательский объект в ellipsis...
RO>Я к тому, что в printf его вообще нельзя нормально вывести, а в std::ostream легко.
Ну это уже отдельная проблема. Если программист повсеместно использует printf, то я думаю он имеет какие-то отработанные решения для этой проблемы.
Здравствуйте, igna, Вы писали:
I>"%s%s" имеет тип array of 5 const char, но неявно приводится не только к pointer to const char, но и к pointer to char:
Конечно, вы правы. Что-то я забыл о том, что функции с аргументами типа char* прекрасно принимают и строковые константы. Кажется, это было сделано для совместимости с С?
CONFORMING TO
These functions are GNU extensions, not in C or POSIX. They are also
available under *BSD. The FreeBSD implementation sets strp to NULL on
error.