2017-05-22 31 views
8

Aşağıdaki kodu:Bir işaretçiyi, yazılan/boyutlandırılmış enum ile bir işaretçiyi temeldeki türe dönüştürmek güvenli midir?

void f(const uint8_t* a) {} // <- this is an external library function 
enum E : uint8_t { X, Y, Z }; 

int main(void) { 
    E e = X; 
    f(&e); // <- error here 
} 

aşağıdaki hatayı üretir: Ben mutlaka o altta yatan türü ile temsil edilir anlamına geleceğini ENUM en tanımında : uint8_t düşündüğü için bana şaşırtıcı

/tmp/c.cc:10:3: error: no matching function for call to 'f' 
    f(&e); 
^
/tmp/c.cc:5:6: note: candidate function not viable: no known conversion from 'E *' to 'const uint8_t *' (aka 'const unsigned char *') for 1st argument 
void f(const uint8_t* e) { } 

. Bence teminat sağlamıyor ben çok fazla sakıncası, ama bunu atlamak için bir hata olduğunu verilen yok

f((uint8_t*)&e); 

, bu her zaman güvenlidir veya : uint8_t: Ben kolayca alçıyla bu sorunun üstesinden gelebilirsiniz bu?

+1

Bunun bir hata olmasını istersiniz. Söz konusu işlev, "enum" unızın dışındaki değerleri atarsa, bunun gerçekleşmesini ister misiniz? "İmzasız" beklediği bir işleve int * 'yi aktarmadan, yayınlamadan izin vermenin iyi bir fikir olduğunu söylemek gibi; elbette, genellikle aynı boydadırlar, ama o zaman bile, bir tanesinin yarısı diğeri için tamamen farklı bir anlama sahiptir. – ShadowRanger

+0

Ve muhtemelen dökümünle katı takma kuralı kırıyorsunuz. – Jarod42

+0

'e ', bellekte bir uint8_t olarak var, bu nedenle döküm güvenli olmalı. – Jacek

cevap

5

Gerçekten güvenli (her ne kadar bir dil avukatım olmamasına rağmen): Bellekte saklanan şey bir uint8_t'dur ve işaret edeceğiniz şey budur. Ancak, f(), const olmayan bir uint8_t için bir işaretçi alacaktıysa, bu değeri, E enum değerlerinden biri olarak açıkça tanımlanmayan bir değere potansiyel olarak değiştirebilir. (Düzeltme) Bu, C++ standardı tarafından açıkça izin verilmiş olsa da, birçok kişi için şaşırtıcıdır (bu noktada aşağıdaki yorumlarda tartışmaya bakın) ve bunun gerçekleşmediğinden emin olmanızı öneririz.

... ama diğerlerinin önerdiği gibi, güvenlik kavramınız nedeniyle hatayı almıyorsunuz, ancak örtülü dönüşümler sivri uçlu türler arasında gerçekleştirilmediğinden. Bir E'u uint8_t alan bir işleve iletebilir, ancak bir uint8_t * alan bir işlev için bir E *; Bu, dil komitesine ve benim düşünceme göre - işaretçi türlerine karşı aşırı şövalye bir tutum olurdu. Bu Afaik

+1

"o zaman bu değer, geçerli bir" E "değeri olmayan bir şeye potansiyel olarak değişiklik gösterebilir - Açık bir temel türdeki numaralandırmalarda, temel türdeki tüm değerler, enum için de geçerli değil midir? – hvd

+1

@hvd: Sanmıyorum, hayır. Bir "enum E" nin tek geçerli elemanları, içinde özel olarak tanımlanmış olanlardır ve AFAIK, bu, alttaki türün belirtilmesiyle gerçekleştirilmez. – einpoklum

+0

"Temel türü sabit olan bir numaralandırma için, numaralandırma değerleri temeldeki türün değerleridir." (n4140 [dcl.enum] p8) – hvd

3

kazara tek yasal geçerli:

Ne yapıyorsun bir reinterpret_cast performans ve ben f içten o işaretçiyi kaldırma edilir varsayıyorum. Bu vakaların çok kısıtlı sette yasal tek ve normatif değil iken, cppreference.com olanların iyi bir genel bakış sağlar: Bu vakaların

Yok bir enum en temel tipi için bir işaretçi döküm içerir!

Ancak: unsigned char* için bir işaretçi Döküm ve çözümleyecek
uint8_t bunun için sadece bir typedef daima yasal ve en platformlarda olduğunu. Yani bu durumda tamam, ancak alttaki tür ör. uint16_t olacaktır.

Bu söylendiği gibi, çoğu derleyicinin standart kullanmasa bile böyle bir kullanıma izin vereceğini duymak beni şaşırtmayacaktır.

İlgili konular