2015-08-19 4 views
2

Безопасно ли переинтерпретировать указатель на неквалифицированный тип в качестве указателя на квалифицированный тип? Рассмотрим стандартный тип макета, содержащий элемент указателя «void * ptr» и другой стандартный тип макета, определенный эквивалентно, но с «const void * ptr». Совместимы ли эти типы с макетами и зависит ли этот ответ от пересмотра языка или между C и C++?Указатель на квалифицированное и неквалифицированное представление типа

Мотивация:

Иногда при взаимодействии с программами C, один определяет параметры структуры группировки к некоторому типу буфера. Для const-correctness входной буфер должен иметь константные указатели на базовые буферы, но выходные буферы, очевидно, должны быть изменчивыми.

struct s1 { const void *ptr; } 
struct s2 { void *ptr; } 

const void *get_in_ptr(void); 
void *get_out_ptr(void); 

void alg(const s1 *in, const s2 *out); 

void f() 
{ 
    s1 in_arg = { get_in_ptr() }; 
    s2 out_arg1 = { get_out_ptr() }; 
    s2 out_arg2 = { get_out_ptr() }; 

    /* First algorithm pass. */ 
    alg(&in_arg, &out_arg1); 
    /* Second algorithm pass. */ 
    alg((const s1 *)&out_arg1, &out_arg2); /* Is this legal? */ 
} 

Просьба привести соответствующие стандартные публикации в любых ответах.

+0

Пожалуйста, предоставьте [mcve]. 'get_in_ptr' и' get_out_ptr' не определены. – Olaf

+0

Я продлил пример. – 68ejxfcj5669

ответ

-1

[C99: 6.2.5/25, C11: 6.2.5/26]:[..] Квалифицированные или неквалифицированные версии типа являются различными типами, которые принадлежат к той же категории типа и имеют то же требование, представительское и выравнивание. [..]

[C++03, C++11, C++14: 3.9.3/1]:[..] СиЗа квалификация или CV-неквалифицированных версии типа различный типа; однако они должны иметь одинаковые требования к представлению и выравниванию (3.11).

И Инкапсулирующие типов:

[C99: 6.2.7/1]:[..] Кроме того, две структуры, объединение или перечисляемые типов, объявленные в отдельных единицах перевода совместимы, если их метки и члены удовлетворяют следующие Требования: если объявлено тегом, другое объявляется с тем же тегом. Если оба являются полными типами, то применяются следующие дополнительные требования: между их членами должно существовать взаимно однозначное соответствие, так что каждая пара соответствующих членов объявляется с совместимыми типами и такая, что если один член соответствующей пары объявленный с именем, другой член объявляется с тем же именем. [..]

[C++03: 9.2/14]: Два POD-Struct (пункт 9) типов макет-совместимый, если они имеют одинаковое количество нестатических элементов данных, а также соответствующий нестатические элементы данных (по порядку) имеет макет-совместимые типов (3,9).

[C++11: 9.2/16, C++14: 9.2/17]: Два типа структуры стандартной компоновки (раздел 9) являются совместимыми с макетами, если они имеют одинаковое количество нестатических элементов данных и соответствующих нестатических элементов данных (в порядке упорядочения) имеют совместимые с макетами типы (3.9).

Итак, если предположить, что мы не обращая внимания на системы типа обхода (const void*void* через const_cast либо непосредственно, либо с помощью C-стиле литые — к сведению, что reinterpret_cast не имеет ничего общего с этим и явно запрещено падать CV- квалификаторы) и только о совместимости aliasing & hellip;

& hellip; да, это «безопасно».

Именно поэтому мы можем использовать const_cast, деликатно, когда древние API, C заставляют нас принимать во внимание их слова, а не на самом деле с помощью const -Безопасность.

Вы знаете, это хорошо в любом случае, потому что, когда вы писали &in_arg ваш компилятор неявно преобразовал s1* в const s1* для вызова, и не жалуются.

+0

Большое спасибо! Должен ли я интерпретировать это как означающее, что структуры «s1» и «s2» совместимы с макетами (или эквивалентной терминологией C)? Кроме того, строго ли сглаживание, чтобы читать значение «in> ptr» в функции «alg», и зависит ли ответ от того, являются ли «in» и «out» одинаковой структурой? – 68ejxfcj5669

+0

@ 68ejxfcj5669: Почему бы вам просто не прочитать стандарт? Вместо того, чтобы потребовать, чтобы я скопировал его здесь? –

+0

«Вы знаете, что все в порядке, потому что, когда вы написали & in_arg, ваш компилятор неявно преобразовал s1 * в const s1 *». Я знаю, что неконстантные указатели конвертируются в константные указатели, но не сразу очевидно, что они должны иметь одинаковое представление. Например, некоторая реализация может добавить бит тега к const-указателям, который запускает ловушку при записи. Во всяком случае, реальный вопрос заключается в том, чтобы сгладить структуры s1 и s2. Я мог бы прочитать стандарт, но я никогда не понимал, как интерпретировать положения строгой алиасии. – 68ejxfcj5669

1

С11 states:

Для любого спецификатора д, указатель на не-Q-квалифицированного типа может быть преобразован в указатель на Q-квалифицирован версии типа; значения, хранящиеся в исходных и преобразованных указателях, сравниваются равными.

Таким образом, это безопасно применять к квалифицированной версии, но не наоборот. Отключение - особенно const, или volatile может использовать различные обращения к памяти, например. для архитектур Гарварда, хранящих const переменных в памяти программ (PIC, AVR). И стандарт очень clear о последствиях:

Если попытка изменить объект, определенный с константным-квалифицированным типом посредством использования Lvalue с неконстантным-квалифицированным типом, поведение не определенно. Если делается попытка обратиться к объекту, определенному с помощью типа с изменчивой квалификацией, с использованием значения lvalue с типом, не зависящим от летучих, поведение не определено.

Вкратце: это не безопасно откинуть эти отборочные в целом. Однако в стандарте не упоминаются образы доступа для ex-const объектов.

Для других квалификаторов и более подробной информации, пожалуйста, прочитайте сами.


Для макета структуры: C использует совместимость по типу/расположению, в отличие от C++. Таким образом, два типа совместимы, если они используют один и тот же макет/стандартный тип, но не одно и то же имя-типа.

+0

Это не отвечает на вопрос. Вопрос в том, безопасен ли листинг _itself_ (который выполняется путем указания указателя на одну структуру в указатель на другую структуру), а не в том, записывает ли оно значение, на которое указывает безопасный указатель. – Random832

+0

@ Random832 Согласен. Вопрос заключается в том, определено ли это, чтобы указать указатели на структуры, содержащие указатели различной квалификации, и прочитать значения этих указателей (а не заостренный объект). – 68ejxfcj5669

+0

@ 68ejxfcj5669: В первом абзаце четко задан вопрос: «Безопасно ли переинтерпретировать указатель на квалифицированный тип в качестве указателя на неквалифицированный тип? ...». Обратите внимание, что C не имеет 'reinterpret_cast', а только cast. Если у вас есть проблема с ответом на C, вы должны пометить свой вопрос только на C++. – Olaf