Гарантирует ли объединение указателя и массива указателей, что единственный указатель имеет тот же адрес, что и первый элемент массива?

Со структурой:

struct stree {
    union {
        void *ob;
        struct stree *strees[256];
    };
};

Гарантируют ли стандарты C (особенно C11), что ob является псевдонимом stree[0]?

Мой вопрос возвращается к вам: почему бы не использовать void * напрямую?

Øystein Schønning-Johansen 20.06.2019 12:54

если бы это был struct stree *ob;, это была бы «общая начальная последовательность»

sp2danny 20.06.2019 12:56
Гарантирует ли объединение указателя и массива указателей, что единственный указатель имеет тот же адрес, что и первый элемент массива?да - Гарантируют ли стандарты C (особенно C11), что ob является псевдонимом stree[0]?Нет (если под псевдонимом вы имеете в виду такое же представление памяти)
David Ranieri 20.06.2019 13:10

@ØysteinSchønning-Johansen strees[0] всегда доступен только как указатель void *. Доступ к массиву улиц осуществляется только через индексы 1-255. Использование объединения позволяет мне сохранить размер как степень двойки, что позволяет избежать использования (void *) в нескольких местах.

fadedbee 20.06.2019 14:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
87
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Может быть. Стандарт C гарантирует только следующее, 6.3.2.3:

A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

Теоретически/формально void* не обязательно иметь то же представление памяти, что и указатель на объект. Всякий раз, когда он сталкивается с таким преобразованием, он теоретически может делать некоторые трюки, такие как отслеживание исходного значения, чтобы восстановить его позже.

На практике void* и указатели объектов имеют одинаковый размер и формат в любой здравомыслящей системе, потому что это, безусловно, самый простой способ удовлетворить вышеуказанное требование. Существуют системы с расширенными режимами адресации для объектов, но они не работают так, как предполагал стандарт C. Вместо этого они используют нестандартные расширения, изобретая квалификаторы указателя near и far, которые затем можно применять либо к void*, либо к указателю объекта. (Некоторыми примерами этого являются недорогие микроконтроллеры и старая MS DOS.)

Итог: проектирование для переносимости на безумные или вымышленные системы — это огромная трата времени. Добавьте static_assert(sizeof(void*) == sizeof(int*), "...") и этого должно быть достаточно. Потому что на практике вы не найдете систему с волшебным или таинственным форматом void*. Если да, то разберитесь с этим.

Однако вы должны иметь в виду, что void* сам по себе является другим типом, поэтому вы обычно не можете получить доступ к памяти, где хранится void*, через другой тип указателя (строгий псевдоним указателя). Но есть несколько исключений из строгого правила алиасинга, одно из них — каламбур через союзы.

Итак, что касается вашего union, void* и первый указатель объекта гарантированно будут выделены, начиная с одного и того же адреса, но опять же их соответствующие размеры и внутренние форматы теоретически могут быть разными. На практике вы можете предположить, что они одинаковы, и поскольку вы используете union, вы не нарушаете строгое сглаживание.

Что касается наилучшей практики, то в первую очередь следует избегать void*, так как очень мало мест, где они действительно нужны. В тех немногих случаях, когда вам нужно передать какой-то общий указатель, часто лучше использовать uintptr_t и сохранять результат как целое число.

Может ли какая-нибудь система разместить ob по тому же адресу, что и streetes[255]?

fadedbee 20.06.2019 13:16

@fadedbee они находятся по одному и тому же адресу во всех системах

David Ranieri 20.06.2019 13:18

@fadedbee Элементы массивов и структур гарантированно размещаются сверху вниз, причем первый член находится на самом низком адресе. Это 100% переносимое предположение, на которое не влияет порядок байтов и т. д. Члены союза гарантированно размещаются на одном и том же адресе.

Lundin 20.06.2019 13:26
near и far не имеют ничего общего с тем, почему разные типы указателей могут иметь разные представления в строго соответствующем коде C или коде в вопросе. near и far являются расширениями, но стандартные char * и int * могут иметь разные представления, и утверждение, что их размеры одинаковы, не будет проверять это.
Eric Postpischil 22.06.2019 12:30

@EricPostpischil near и far — единственный реальный пример указателей разных форматов, которые существуют на обычных компьютерах. Другие формы внутренних форматов магических указателей не существуют в нормальных системах, несмотря на то, что говорит стандарт.

Lundin 24.06.2019 08:53

Нельзя сделать так, чтобы квадратный штифт помещался в круглое отверстие, заявляя, что круглых штифтов нет: заявления об отсутствии других примеров не устраняют дефект, заключающийся в том, что near и far не являются примерами разных типов указателей, имеющих разные представления в строго соответствующем коде C. или код в вопросе. Указатели near и far просто не имеют отношения к тому, имеет ли void * то же представление, что и struct stree *. Квадратный стержень языковых расширений не помещается в круглое отверстие строго соответствующего кода.…

Eric Postpischil 25.06.2019 01:06

… Они не имеют отношения к проблеме и представляют собой отступление, которое сбивает этот ответ с рельсов. Кроме того, не нужно проверять размеры указателей, чтобы узнать, являются ли они проблемой: это можно узнать, потому что исходный код содержит near или far.

Eric Postpischil 25.06.2019 01:06

Можно легко привести примеры систем, в которых адреса имеют или имели разные представления для разных типов объектов, включая HP 3000 (который сегодня имеет постоянную стороннюю поддержку, в том числе для GCC), PDP-10 компании Digital, некоторые машины Cray, некоторые машины Prime. и серия Eclipse MV компании Data General. Это послужит информированию людей о том, почему эти лицензии были предоставлены в стандарте C, и позволит им принимать обоснованные решения, основанные на соответствующих фактах, а не на неуместных отступлениях.

Eric Postpischil 25.06.2019 01:10

Другие вопросы по теме