Возвращают char вместо const char? Может я упускаю какой-то сакральный смысл? Просто преобразование `return (char *)s;`, нарушает все допустимые нормы программирования (MISRA, NASA JPL, etc). Да и просто по логике - взяли константную строку на вход, на выходе позволяем делать с ней все, что угодно.
Если ты хочешь чтобы тебя били по рукам, когда ты подсунул const char* в такие функции, а присваиваешь переменной char*, то компилируй C код C++ компилятором.
#include <cstring>
int main()
{
const char *str = "Try not. Do, or do not. There is no try.";
char target = 'T';
char* result = std::strchr(str, target);
}
main.cpp error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
char* result = std::strchr(str, target);
<встроенное>: ошибка выполнения рецепта для цели «src/main.o»
make: *** [src/main.o] Ошибка 1
Конечно. Ибо менять или не менять далее — решать программисту, а не вышевызванной функции. Она закончилась. Можно ли менять память по возвращенному смещению от переданного аргумента она не знает. И слава богу.
Да и просто по логике - взяли константную строку на вход, на выходе позволяем делать с ней все, что угодно.
а как по вашему, зачем ЭТИ функции возвращают «char *» ?? для чего они служат и зачем нужны. Директивно вернуть из них (еретичный для C) const - просто убить их функционал и цель существования.
int strstr(const char *haystack, const char *needle);
char * found = hay + strstr(hay, ndl);
?
Тогда никаких претензий не было бы. И stdlib заодно стал бы соответсвовать стандартам безопасности:
All libraries used in production code shall be written to comply
with the provisions of this document, and shall have been subject
to appropriate validation.
[IEC 61508 Part 3]
Во-вторых, size_t на 33 бита длиннее, чем int в 64 мире
Я повторюсь, есть такая вещь как ssize_t.
-1 как код возврата в случае есть функция чего-то не нашла - вполне разумное решение, так как любая си-функция работы со строками, которая возвращает char * требует проверки на NULL. В случае возврата ssize_t эта проверка просто изменится на if (... < 0)
Этот тип появился не от хорошей жизни. Он применяется для костыльного API read/write, так как 50 лет назад никто не задумывался, что 2 Gb файл это не так уж и много, потом согласились, что типа (4Gb - errno) это тоже нормальный такой предел. Короче, если б сразу был бы аргумент для ошибки у read/write, то типа ssize_t вообще бы не было. Для строк этот тип вообще не юзается.
оторая возвращает char * требует проверки на NULL.
NULL хорош прежде всего тем, что это недопустимое значение для использования. Потому можно передавать скажем во free(NULL) и так далее. В вашем же API придётся передавать два аргумента в более глубокие функции: prt и ssize_t, потом проверять на -1. Это - УРОДСТВО.
NULL хорош прежде всего тем, что это недопустимое значение для использования.
На который ВСЕГДА нужно проверять (кроме исключения в free, но оно там тоже не сразу появилось). ВСЕ остальные функции не могут нормально обработать NULL.
В случае < 0 ты делишь максимальное значение результата на два
О, ещё один срыватель покровов. Да мелочи это. Важно то, что ваша my_find_str должна передавать в более глубокие функции уже не только ptr, когда он NULL=«не нашла» или валидное смещение, а ssize_t и ptr, ибо prt-1 - это валидный адрес в 99.(9)% случаях.
Ничерта то вы ничего не поняли. free() тоже проверяет. Но именно об этом я и говорю, о API всех функций программы. Ибо free() проверяет только ptr, а не ptr + flag валидности.
Действительно, можно еще как в паскале для строк байтом обойтись. Да и тип size_t выкинуть как бесполезный, есть же int. Без подобных мелочей можно прожить.
Важно то, что ваша my_find_str должна передавать в более глубокие функции уже не только ptr, когда он NULL=«не нашла» или валидное смещение, а ssize_t и ptr, ибо prt-1 - это валидный адрес в 99.(9)% случаях.
Что за норкомания? my_find_str вернет только ssize_t (кстати нестандартный тип), а на месте вызова либо будет создан новый валидный указатель, либо NULL. Куда ты собрался передавать пару?
Действительно, можно еще как в паскале для строк байтом обойтись. Да и тип size_t выкинуть как бесполезный, есть же int. Без подобных мелочей можно прожить.
Это вы со своим альтерэго разговаривали?
кстати нестандартный тип
Ну дык.
а на месте вызова либо будет создан новый валидный указатель, либо NULL
Охренеть удобство. То есть я уже не смогу вызвать my_show(my_find_str())?
Причем тут это? Ты сказал, что смена типа на неравнозначный по диапазону - мелочь, а теперь начинаешь вилять.
Врать не надо. Я сказал, что по сравнению с уродованием API ваш старший бит - мелочи. Покажите данные в 63 бита размерности? А вот API предлагаете изуродовать сейчас.
Да и вообще. ТС на бегу поменял int на ssize_t, то есть таки вспомнил о потеряных аж 32 битах. А вы предлагаете, в лучших традициях модно-молодёжно «старики идиоты и надо всё сделать ровно по другому» уродливое API, оправдывая, что подумаешь, можно же -1 зарезервировать.
все строковые функции С выпадут в осадок из-за NULL.
И это хорошо. Ибо у нас тут не ява, хотите скорости — проверяйте там где надо руками, а не чтобы оно на каждом шаге спотыкалось вдруг чего.
Врать не надо. Я сказал, что по сравнению с уродованием API ваш старший бит - мелочи
Какой «мой» старший бит? Я за указатели.
Покажите данные в 63 бита размерности?
А кто тебе сказал, что в С size_t - 64 бита? Кто тебя так жестоко обманул?
вы предлагаете, в лучших традициях модно-молодёжно «старики идиоты и надо всё сделать ровно по другому»
Я вообще ничего не предлагаю, я против ssize_t.
Ибо у нас тут не ява, хотите скорости — проверяйте там где надо руками, а не чтобы оно на каждом шаге спотыкалось вдруг чего.
Все еще веселее, у нас тут не ява, хотите скорости - забейте на str* функции, ибо это больше симулятор бесполезной беготни по памяти чем API для быстрой и удобной работы со строками.
Это я сказал, для примера. Могу себе позволить, ибо начинал с типичного тогда 35 лет назад 16 бит, а теперь типичное - 64. Хотя даже поигрался на AS400 с их 128...
забейте на str* функции
А, это вы Брут... Я подростковый инфантильный нигилизм не лечу, это не ко мне. Я могу и на ash/bash/awk/sed если можно написать, и mem*() тоже умею, возможно не хуже вашего.
Это я сказал, для примера. Могу себе позволить, ибо начинал с типичного тогда 35 лет назад 16 бит, а теперь типичное - 64. Хотя даже поигрался на AS400 с их 128...
И теперь ты решил отменить все что меньше 64 бит? Хотя да. ты же «можешь себе позволить».
Я подростковый инфантильный нигилизм не лечу, это не ко мне. Я могу и на ash/bash/awk/sed если можно написать, и mem*() тоже умею, возможно не хуже вашего.
Это не нигизм, а адекватность. С имеет слишком много недостатков и ограничений, чтоб без острой необходимости использовать его для написания не критичного к быстродействию кода.
не пользуй это говно времен PDP-11. Пользуй <algorithm>. Он перекрывает всё это барахло по функционалу, типобезопасности, производительности, гибкости.
Example:
struct A { int x; int y; int z; };
A a{.y = 2, .x = 1}; // error; designator order does not match declaration order
A b{.x = 1, .z = 2}; // ok, b.y initialized to 0
Переход на личности? Ок. Много. Из того, что с ходу вспомню:
библиотека ввода\вывода для байт-потоков RS-232. Используется в испытательных стендах пьезоэлектрических материалов в НКТБ «Пьезоприбор»
библиотека базовых типов для памяти-безопасных функций без зависимости от stdlib - строки, байты, конвертации, мьютексы, вот это все. Используется в софте, который сейчас установлен в 90% кинотеатров России и частично в СНГ (Казахстан, Белоруссия).
несколько библиотек анализа памяти
библиотека конвертации вложенных структур с бинарной поддержкой перловых nfreeze/thaw. Используется опять в кинотеатрах.
библиотека поддержки различных протоколов обмена (начиная от binary-modbus, заканчивая xml-over-ssl). Имеет самогенерируемый код по таблицам. Используется в кинотеатрах как часть ТМС.
Это те, которые активно используются в проде. Есть еще proof-of-concepts, just-for-fun проекты и пр. (например конвертации PNG в [ bb ])
Все правильно делают. Порядок важен т.к. это вам не С, тут конструкторы могут отрабатывать. А инициализация по дефолту во-первых удобно, во-вторых безопасно. Совместимость с С она не ломает, а кому очень надо оптимизация - дернет нужные поля по отдельности.
Может и правильно, только это не о совместимости с Си.
Писать код, который соберется и в С и С++, будет работать аналогично, и не будет напрягать при написании (порядок и так обычно сохраняют) - можно, и в большинстве случаев для этого даже ничего не надо дополнительно делать. Значит о совместимости. С++ никогда не был на 100% совместим со всем С, всесто этого есть полноценное и самодостаточное подмножество С и С++, которое постоянно расширяют при выходе новых версий С. И это правильный путь, который позволяет без особых проблем совмещать два языка в рамках одного проекта.
Насчёт «порядок и так обычно сохраняют» - неочевидно. За порядком инициализации в этом случае обычно не следят, и это отличная фича языка, когда ты можешь поменять местами элементы структуры (чтобы они компактнее разместились, например), а на коде инициализации это никак не отразится.
За порядком инициализации в этом случае обычно не следят, и это отличная фича языка
Нет, как и многое в С, это не отличная, а отличительная черта языка. Забивать на типы, забивать на порядок, забивать на константность, забивать на управление ресурсами и пр.
ты можешь поменять местами элементы структуры (чтобы они компактнее разместились, например), а на коде инициализации это никак не отразится.
А еще можно тип элемента поменять на несовместимый (int* на double*, например) и тоже «на коде инициализации это никак не отразится».
Поясню - иногда нет возможности использовать stdlib. Неважно почему - для микроконтроллера или какой-нибудь еще встроенки. Тогда пишется своя реализация (или покупается чужая (или берется жирный прежирный stdlib от glibc\etc, но он жирный\не обеспечивает что-то специфичное для процессора\платформы)).
Так вот. Вот это: