#c #string #struct #void-pointers
#c #строка #структура #void-указатели
Вопрос:
Я реализую a CMap
в C, и часть этого связана с хранением информации в структуре типа связанного списка, памятью которой я управляю вручную. Итак, первые 4 байта этого struct
являются указателем на следующий struct
, следующий раздел — это строка (ключ), а последний раздел — это значение.
Скажем void *e = ptr
, определяет один такой связанный список. Затем ptr 4
ссылается на начало строкового раздела. Я хочу присвоить это строковое значение другой строке, и то, что я сделал до сих пор, это:
char *string = (char *)ptr 4;
Однако я не думаю, что это правильно.
Комментарии:
1. Почему вы не можете выполнить приведение к структуре, а затем использовать
->
оператор для доступа к полю?2. Откуда вы знаете длину строки? Он завершается нулевым байтом? И что именно вы пытаетесь сделать? Вы пытаетесь сделать копию строки? Или просто получить к нему доступ? Если это строка в стиле C с нулевым завершением, и вы просто хотите получить доступ к ее значению,
char *string=(char *)ptr 4;
все в порядке. (Хотяsizeof(void *)
было бы лучше, чем 4 — код, возможно, в конечном итоге потребуется запустить на платформе LP64.)
Ответ №1:
Если вы хотите указать на одну и ту же строку, ваш код в порядке, предполагая, что указатели всегда имеют ширину 4 байта.
Если вы хотите скопировать содержимое строки, используйте malloc и strcpy для создания новой строки.
Ответ №2:
Просто ссылайтесь на struct вместо вычисления смещений.
//if data is structured this way
struct struct_list_el
{
struct list_el * next;
char* str;
int value;
};
typedef struct struct_list_el list_el;
// than from void_pointer
list_el* el;
el = (list_el*) void_pointer;
char * string;
string = el->str;
Комментарии:
1. Если вы используете структуру, вы должны убедиться, что все правильно выровнено в памяти, иначе вы получите ошибку шины на некоторых архитектурах (например, m68k).
2. @hochl Что? разница с m68k заключается в том, что они имеют большой конечный код, в то время как PC имеет маленький конечный код. Это означает, что отправка целого числа с одного компьютера на другой может вызвать проблемы.
3. Я помню, что на m68000 доступ к чему-либо, превышающему байт, по нечетному адресу приведет к ошибке шины, но это было в 80-х годах, возможно, более новые модели не выдают ошибку шины в таких ситуациях и разделяют доступ к памяти на два доступа внутри. В любом случае, компилятор обычно вставляет байты заполнения, чтобы все элементы структуры имели доступное смещение (обычно даже для чего угодно, кроме байта).
4. Вы можете использовать макрос #pragma pack(1) для упаковки структуры. У меня нет проблем с использованием этого подхода в coldfire.
Ответ №3:
@ralu прав, что вы должны использовать структуру. Но вы также должны быть очень осторожны при копировании строк. В C нет первоклассного строкового объекта, как в C , Java, Python и, ну, во всем остальном. 🙂
В C символьные указатели ( char*
) часто используются как строки, но на самом деле это просто указатели на массивы байтов с нулевым завершением где-то в памяти. Копирование символьного указателя — это не то же самое, что копирование базового массива символов. Для этого вам необходимо предоставить память для символов копии. Эта память может находиться в стеке (локальном массиве), или в куче (созданной с помощью malloc), или в каком-либо другом буфере.
Вам нужно будет измерить длину строки, прежде чем что-либо делать, чтобы убедиться, что целевой буфер может ее удерживать. Обязательно добавьте единицу к длине, чтобы было место для завершающего значения null .
Также обратите внимание, что стандартные библиотечные функции (strlen, strcpy, strncpy, strcat, snprintf, strdup и т.д.) немного несовместимы друг с другом в отношении завершающего значения null. Например, strlen возвращает количество символов, исключая завершающий null , поэтому буферы должны быть на один байт больше, чем то, что он возвращает для хранения вещей. Кроме того, strncpy не гарантирует нулевое завершение, в то время как snprintf гарантирует. Неправильное использование этих функций и строк C в целом является причиной значительного числа нарушений безопасности (не говоря уже об ошибках) в компьютерных системах сегодня.
Если вы не создаете или не используете надежную библиотеку, работа со строками и списками в C утомительна и подвержена ошибкам. Вы можете понять, почему C и все эти другие языки были изобретены.