2014-01-07 5 views
1

У меня есть макрос, который должен иметь возможность принимать произвольные целые числа или типы указателей и преобразовывать их в unsigned long long. Естественный способ сделать это - просто бросить, и это работает, но с предупреждениями GCC по умолчанию он дает «отбрасывание от указателя до целого разного размера», и я бы хотел этого избежать. Естественный способ избежать предупреждений является с промежуточным гипсе, как в (unsigned long long)(uintptr_t)x, но это не работает в моем случае, потому что:Альтернатива без знака без знака

  1. Это усечения целых входов, которые не помещаются в uintptr_t.
  2. Он нарушит правильное преобразование подписанных входов, например. -1 может стать 0xffffffff вместо 0xffffffffffffffff.

Если бы я имел выражение (возможно, делая фантазию использование оператора ?:), которые могли бы отличить указатель от целочисленных типов, я мог бы разбить его в двух случаев и применить (uintptr_t) бросок первым для входов указателя, но не для целочисленные. Какие-нибудь идеи об уловке, которые будут работать?

+2

(поистине ужасно, только для безумных): '_Generic' с футляром для каждого целочисленного типа. –

+0

@ StephenCanon: Справедливости ради, вы можете сделать это немного менее страшным, применив операцию, которая выполняет целые рекламные акции, но это также безопасно применять к указателям, тем самым устраняя все те, у которых более низкий ранг, чем 'int'. '1? X: 0' должен работать. –

+1

Или даже лучше: примените '1? X: (uintmax_t) 0', принудительно применяя любой целочисленный тип к' uintmax_t' для целей '_Generic', оставив типы указателей нетронутыми. К сожалению, для этого все еще требуется поддержка C11, которая не получила широкого распространения. –

ответ

1

Это кажется, что это должно работать:

sizeof (1?(x):(unsigned long long)0) < sizeof (unsigned long long) 
    ? (uintptr_t)(x) 
    : (unsigned long long)(x) 

случаях:

  1. x имеет любой целочисленный тип. Затем 1?(x):(unsigned long long)0 имеет тип unsigned long long и, таким образом, берется вторая ветвь, конвертирующая непосредственно в unsigned long long.
  2. x имеет тип указателя и тип указателя меньше unsigned long long. Затем 1?(x):(unsigned long long)0 имеет оригинальный тип указателя и берется первая ветка, проходящая через uintptr_t.
  3. x имеет тип указателя и тип указателя того же размера (или больше, но я предполагаю, что этого не происходит) как unsigned long long. Затем берется вторая ветка, но в любом случае предупреждения не должно выдаваться.

Я не ясно, если GCC может избежать выдачи предупреждения о мертвом кода (ветвь, которая не будет принято), но если нет, то, возможно, __builtin_choose_expr решение.

Смежные вопросы