Почему делает эту реализацию offsetof () работа?

Вы просто разбиваете строку разделенных новой строкой полей. У объекта String в Ruby есть метод split, который делает это.

my_string = "John Clark\nDallas\nSystem Engineer\nGlobal Edge\nWage 2\nY\n1\nRobin James\nCleveland\nArchitect\nMaxSys\nWage 3\nY\n0\nJoseph Neils\nLittle Rock\nDB Admin\nTech Sys\nWage 2\nY\n1\n"
my_string.split("\n")

дает вам массив строк, такой как вы хотите. Затем вы можете объединить эти массивы в другой массив.

Документация по методу разделения здесь: https://ruby-doc.org/core-2.6.2/String.html#method-i-split

32
задан M.M 13 November 2014 в 10:08
поделиться

6 ответов

Ни в каком смысле в вышеупомянутом коде что-либо разыменованное. Разыменовывание происходит когда * или -> используется на значении адреса для нахождения значения, на которое ссылаются. Единственное использование * выше находится в описании типа в целях кастинга.

-> оператор используется выше, но он не используется для доступа к значению. Вместо этого это используется для захвата адреса значения. Вот немакро-пример кода, который должен сделать это немного более ясным

SomeType *pSomeType = GetTheValue();
int* pMember = &(pSomeType->SomeIntMember);

Вторая строка на самом деле не вызывает разыменовывание (зависящего от реализации). Это просто возвращает адрес SomeIntMember в pSomeType значение.

То, что Вы видите, является большим количеством кастинга между произвольными типами и символьными указателями. Причина символа состоит в том, что это - один из единственного типа (возможно, единственное) тип в стандарте C89, который имеет явный размер. Размер равняется 1. Путем обеспечения размера один, вышеупомянутый код может сделать злое волшебство вычисления истинного смещения значения.

33
ответ дан 27 November 2019 в 20:30
поделиться

В ANSI C, offsetof НЕ определяется как этот. Одна из причин, это не определяется как этот, - то, что некоторые среды действительно бросят исключения нулевого указателя или откажут другими способами. Следовательно, ANSI C оставляет реализацию offsetof( ) откройтесь разработчикам компилятора.

Код, показанный выше, типичен для компиляторов/сред, которые активно не проверяют на Нулевых указателей, но перестали работать только, когда байты читаются из Нулевого указателя.

9
ответ дан 27 November 2019 в 20:30
поделиться

Для ответа на последнюю часть вопроса код не является портативным.

Результат вычитания двух указателей определяется и портативный, только если эти два указателя указывают на объекты в том же массиве или указывают на одно прошлое на последний объект массива (7.6.2 Аддитивных операторов, H&S Пятый Выпуск)

8
ответ дан 27 November 2019 в 20:30
поделиться

Хотя это - типичная реализация offsetof, это не получает мандат по стандарту, в котором просто говорится:

Следующие типы и макросы определяются в стандартном заголовке <stddef.h> [...]

offsetof(type,member-designator)

который расширяется до выражения целочисленной константы, которое имеет тип size_t, значение которого является смещением в байтах к элементу структуры (обозначенный member-designator), с начала его структуры (обозначенный type). Тип и членский указатель должны быть таковы что данный

statictypet;

затем выражение &(t.member-designator) оценивает к постоянному адресу. (Если указанный участник является битовым полем, поведение не определено.)

Считайте P J Plauger "Стандартная библиотека для C" для обсуждения его и других объектов в <stddef.h> которые являются всеми пограничными функциями, которые могли (должен?) быть на надлежащем языке, и который мог бы потребовать специальной поддержки компилятора.

Это представляет исторический интерес только, но я использовал ранний компилятор C ANSI на 386/IX (см., я сказал Вам об историческом интересе, приблизительно 1990), который отказал на той версии offsetof но работал, когда я пересмотрел его к:

#define offsetof(st, m) ((size_t)((char *)&((st *)(1024))->m - (char *)1024))

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

9
ответ дан 27 November 2019 в 20:30
поделиться

Это не делает segfault, потому что Вы не разыменовываете его. Адрес указателя используется в качестве числа, это вычтено из другого числа, не используемого для обращения к операциям памяти.

2
ответ дан 27 November 2019 в 20:30
поделиться

Это вычисляет смещение участника m относительно начального адреса представления объекта типа st.

((st *)(0)) относится к a NULL указатель типа st *. &((st *)(0))->m относится к адресу участника m в этом объекте. Так как начальный адрес этого объекта 0 (NULL), адрес участника m является точно смещением.

char * преобразование и различие вычисляют смещение в байтах. Согласно операциям указателя, когда Вы имеете значение между двумя указателями типа T *, результатом является количество объектов типа T представленный между двумя адресами содержится операндами.

2
ответ дан 27 November 2019 в 20:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: