Как присвоить строковое значение в C из void *?

#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 и все эти другие языки были изобретены.