LINUX.ORG.RU

Как красиво присвоить строковое поле?

 


1

2

Здравствуйте

Пусть есть структура foo с полем char s[8]

Чтобы присвоить полю значение надо написать аж 2(!) строки )

memset(foo.s, 0, sizeof(foo.s));
memcpy(foo.s, mystring, strlen(mystring));

Может есть способ поэлегантнее?

★★★★★

Вы всё ещё копируете строки 8 байт ?

/// hindicode :-)
((foo.s[0]=mystring[0])||
(foo.s[1]=mystring[1])||
..
(foo.s[7]=mystring[7]));

это к чему...а к тому что в С есть 1000 и 1 способ стрелять в ногу сделать всё что угодно ;-) и всегда есть выбор

MKuznetsov ★★★★★
()
Ответ на: комментарий от arturpub

Потому что ни низкий уровень не осилили, ни высокий

Человек, предложивший кривой по своей природе strncpy, да еще и для копирования восьми байт, что-то вещает про осиливание...

anonymous
()
Ответ на: Вы всё ещё копируете строки 8 байт ? от MKuznetsov

это к чему...а к тому что в С есть 1000 и 1 способ стрелять в ногу сделать всё что угодно ;-) и всегда есть выбор

1000 и 1 способ есть, а правильный никто не знает, в отличие от других языков, где есть тот же 1000 и 1 способ, но один - общепринятый и очевидный правильный.

anonymous
()
Ответ на: комментарий от makoven

А что кривого в strncpy?

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
    char s[4];
    strncpy(s, "fail", sizeof(s));

    printf( "%s\n", s);
    
    return 0;
}

Поведение такой программы зависит от фаз луны. У кого-то креш, у кого-то мусор на экране, а у кого-то все будет работать нормально, пока не попадет к пользователю.

anonymous
()
Ответ на: комментарий от vromanov

У меня тоже есть свой велосипед для платформ, где нет кошерного strlcat :)

#if defined(__linux__)
#define strlcpy(d,s,l)  (strncpy(d,s,(l) - strlen(d) - 1), (d)[(l) - 1] = '\0')
#define strlcat(d,s,l)  strncat(d,s,(l) - strlen(d) - 1)
#endif

https://www.openbsd.org/papers/strlcpy-slides.ps

beastie ★★★★★
()
Ответ на: комментарий от anonymous

Конечно это все можно подпереть костылем (причем не одним), но поведение для этой функции выбрано откровенно норкоманское.

anonymous
()
Ответ на: комментарий от beastie

(strncpy(d,s,(l) - strlen(d) - 1), (d)[(l) - 1] = '\0')

Жесть. Я даже не стану перечислять ошибки в этой строке, их концентрация зашкаливает.

anonymous
()
Ответ на: комментарий от anonymous

Не говоря уж про то, что это еще и подсовывается вместо strlcpy, у которой, внезапно, еще и результат возвращается.

anonymous
()
Ответ на: комментарий от makoven

a snprintf обрежет «l» у «fail» и запишет туда нолик, правильно я понимаю?

Да, но если использовать snprintf для копирования строк, то а зачем вообще тогда использовать С? Другие языки дадут куда более простой и быстрый способ. Это не к тому, что С не нужен, а к тому, что нужно им уметь пользоваться и понимать что к чему. А без этого понимания остаются только пустые понты - я у мамы хакер, пишу на С.

anonymous
()
Ответ на: комментарий от anonymous

Эпичный топик по конкатенации строк на С уже был

Ну, извините) Пока использую bstrlib. В ней помимо malloc-овых функций есть семейство функций, оборачивающих произвольные куски памяти в структуру bstring. Можно даже извратиться и передать Boxed-литерал в качестве аргумента функции с помошью C99 compound structs:

#define L2B(str) &(struct tagbstring) bsStatic(str)

Правда, удобство пользования этим хозяйством оставляет желать лучшего. Может в glib с этим лучше..

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от makoven

Пока использую bstrlib

Не стоит.

Может в glib с этим лучше.

А это вариант. Но опять же - нужно понимать где и зачем оно надо. Иначе это будет бессмысленная реализация того, что на Rust/C++ будет и компактнее, и безопаснее, и быстрее. Я бы посоветовал попытаться остаться на голом С и набить шишек (если это обучение), или выбрать другой язык, если это решение практической задачи.

anonymous
()

strlcpy, если нет в библиотеке то можешь написать свой аналог.

void strcpy_safe(char *dst, const char *src, size_t size) {
    memcpy(dst, src, size-1);
    dst[size-1] = '\0';
}
vcore1v
()
Ответ на: комментарий от vcore1v

Треш-парад продолжается.

1. Ты будешь копировать из src возможно больше, чем src вмещает. Итого - лишний оверхед + возможность креша из-за выхода за границы.
2. Если size будет равен 0, то будет практически гарантированный креш.

Ладно, не буду портить себе настроение, продолжайте без меня.

anonymous
()
Ответ на: комментарий от anonymous

1. Ты будешь копировать из src возможно больше, чем src вмещает. Итого - лишний оверхед + возможность креша из-за выхода за границы.

Можешь привести пример? Не совсем понял что ты имеешь ввиду.

2. Если size будет равен 0, то будет практически гарантированный креш.

Тут согласен, но даже пустая строка - это уже 1 байт, так что явление крайне редкое и легко ловиться дебаггером.

vcore1v
()
Ответ на: комментарий от vcore1v

Safe!! Берите и юзайте....

Фанфары size=0!! В большинстве случаев следует думать при кодинге вместо мучительной отладки.

MKuznetsov ★★★★★
()
Ответ на: комментарий от vcore1v

Можешь привести пример? Не совсем понял что ты имеешь ввиду.

Если это аналог strlcpy, то size - размер dst, и никто не гарантирует, что размер src не может быть меньше. Если size - длина строки src, то "-1" очевидно логическая ошибка. Если size - длина строки src + один байт для 0, то эта функция бесполезна, т.к. является аналогом memcpy(dst, src, size).

anonymous
()
Ответ на: комментарий от anonymous

и никто не гарантирует, что размер src не может быть меньше

Если size больше размера dst то это уже проблемы того кто пишет код

vcore1v
()
Ответ на: комментарий от vcore1v

Если size больше размера dst то это уже проблемы того кто пишет код

#include <stdio.h>
#include <string.h>

struct foo_t
{
    char dst[7000000];
    char src[4];
};

void strcpy_safe(char *dst, const char *src, size_t size) {
    memcpy(dst, src, size-1);
    dst[size-1] = '\0';
}

int main(int argc, char **argv) {
    struct foo_t f;
    f.src[0] = 0;

    strcpy_safe(f.dst, f.src, sizeof(f.dst));

    printf( "%s\n", f.dst);

    return 0;
}

Подумай, почему на типичном линуксе здесь будет креш в твоей функции.

anonymous
()
Ответ на: комментарий от anonymous

Да, сразу отмечу, что это не связано с доступом к dst, он полностью доступен на стеке в типичных 8Мб на чтение и запись.

anonymous
()
Ответ на: комментарий от anonymous

И как дополнительный «бонус» - помимо оверхеда данная функция позволяет скопировать данные за пределами src, что может быть использовано для получения доступа к данным, которые автор не хотел бы выставлять в общий доступ.

anonymous
()
Ответ на: комментарий от anonymous

Я понимаю почему тут будет креш, да, ты прав, я перепутал memcpy с strncpy так как писал по памяти, только что заглянул в свой код, а там strncpy. Извиняюсь.

vcore1v
()
Ответ на: комментарий от vcore1v

Я понимаю почему тут будет креш, да, ты прав, я перепутал memcpy с strncpy так как писал по памяти, только что заглянул в свой код, а там strncpy. Извиняюсь.

Нет проблем. Тогда это просто альтернатива макросу, предложенному выше. Это, конечно, лучше чем макрос, но и не аналог strlcpy, т.к. тот возвращает длину, которую можно использовать, чтоб определить - хватило ли буфера, плюс обработать и сохранить ее, если что.

anonymous
()
Ответ на: комментарий от anonymous

Ты не видишь разницы между fixed width полями и nul-terminated строками, чему ты можешь кого-то научить? Иди крестокубики складывай.

arturpub ★★
()
Ответ на: комментарий от makoven

Все верно, snprintf запишет не более переданного n, включая '\0', который будет там по-любому.

arturpub ★★
()
Ответ на: комментарий от arturpub

Ты не видишь разницы между fixed width полями и nul-terminated строками,

Т.е. ты считаешь, что массив символов в структуре - это однозначно «fixed width поле», или что «nul-terminated строки» в таких массивах нельзя копировать иначе как через итерацию или без вычисления длины?

чему ты можешь кого-то научить?
Иди крестокубики складывай.

Сходи к психологу, ты неадекватен и бросаешься на людей.

anonymous
()
Ответ на: комментарий от anonymous

Если не считать опа идиотом, который копирует strlen(s) > 8 в это поле, то судя по его же примеру ему нужно записать туда строку, которая априори-уверенно до восьми символов и занулить остальное. Большего он не просит, а strncpy собственно это и делает. Если бы оп был озабочен nul-терминацией в фикседе, он бы явно сказал об этом. Если у него строки от нуля до семи включительно, то strncpy под задачу подходит полностью, включая \0. Если до восьми, то очевидно, что он подразумевает нетерминированность, и strncpy под задачу подходит полностью. В противном случае он стреляет себе в ногу, но это его проблемы, и не надо его оберегать — без опыта не придет понимания.

Тебе нужно просто научиться доверять людям, а также безопасно выводить такие поля, например через printf(«%.*s», (int)sizeof(s), s), чтобы вопросы типа «а что будеш делать смотри как %s вылетает» снимались сами собой. Понять, что в char * и char [8] обычно вкладывается разная семантика, и не мешать все в кучу.

неадекватен

В такие треды всегда набигают яумамы-умники со своими хрестоматийными поучениями, так почему бы их не выгнать? Лор грязнет в них, а модераторы некомпетентны, и временами кто-то должен проводить санацию. Иначе тут начнется второй опеннет или что похуже. Ничего личного, мужик.

arturpub ★★
()
Последнее исправление: arturpub (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.