Кажется, что младший бит указателей, равный 0, является более или менее довольно переносимым (где переносимость, очевидно, не означает «стандартный», но людям это сходит с рук, и в некоторых случаях они могут использовать это с некоторым преимуществом, надеюсь, можно отключить с помощью переключателя компиляции).
Проекты, которые хотят быть неудобными, использовали его, с меньшим успехом на втором младшем бите:
Насколько переносимым является использование низкого немного указателя в качестве флага?
Но скажем, не хочется просто совать бит данных или нет в указатель известного типа. Вместо этого вы хотели бы использовать этот младший бит, равный 0, чтобы позволить типу указателя выполнять «двойную функцию» в качестве терминатора.
Таким образом, ваши элементы выглядят так:
struct Item {
uintptr_t flags; // low bit zero means "not an item"
type1 field1;
type2 field2;
...
};
Затем вы хотели бы иметь ситуацию, когда некоторый контейнер элементов выглядит следующим образом:
[(flags field1 field2...) (flags field1 field2...) some-pointer stuff stuff...]
Таким образом, вам сойдет с рук «невозвратная стоимость» (скажем, какой-то внутренний указатель управления в структуре данных для другой цели), который сделает ваше завершение за вас.
ОБНОВЛЕНИЕ: Чтобы прояснить ситуацию: здесь можно контролировать кодовую базу и структуры. Таким образом, любой указатель в структуре, используемой таким образом, вы можете объявить как тип объединения, например:
union Maybe_Terminator_Pointer {
uintptr_t flags;
type1* pointer1;
type2* pointer2;
...
};
... и затем используйте это, если это поможет. Исключение char*
— это нормально, так как они, конечно, не будут учитываться.
Таким образом, дополнительная проблема с каламбуром здесь заключается в следующем: указатель, используемый для выполнения теста на завершение, представляет собой Item*
, а подпрограмма, выполняющая проверку, не знает, какой конкретно тип указателя some-pointer
.
Мне интересно, какова лучшая игра, если таковая имеется, для возможности переноса и компиляции такого трюка. Это включает в себя преобразование указателей в союзы, #ifdef'ing endianness машины и получение char* из байта с битом и т. д. Все, что может больше сработать, если у кого-то есть опыт или догадки.
Представьте, что в вашем случае стоит затраченных усилий, избавившись от большого объема данных. И у вас есть резервный сценарий, если люди, компилирующие, обнаружат, что трюк где-то не работает... #ifdef может использовать полноразмерные элементы для терминаторов и тратить дополнительное пространство. Поэтому интересно, есть ли какие-нибудь советы, как сделать этот явно нарушающий стандарты трюк более эффективным на большем количестве систем.
packed
struct
s, LSB вообще недоступны. Если у вас нет реальных ограничений памяти, дополнительный код не стоит хлопот. И если у вас есть проблемы с памятью, у вас все равно есть конкретная система. Тем не менее, это далеко за пределами стандарта C. - person too honest for this site   schedule 10.01.2016char
указателей. Так что, по крайней мере, вы сможете сделать это только для указателей на типы данных, адреса которых гарантируют 0 младших битов, и это не будет переносимым. - person Tom Karzes   schedule 10.01.2016uintptr_t
с указателями (что и предполагается) - person M.M   schedule 19.01.2016