Bir boş işaretçinin (void *) iki veri türünden biri olup olmadığını nasıl doğrularım?


10

2 types parametrelerini kabul etmek istediğim bir fonksiyon yazıyorum .

  • A string(karakter *)
  • A structuresayısı n olacak.

Ve bunu başarmak için basit bir void *parametre türü kullanmayı düşünüyorum . Ancak parametrenin bir tür veya diğeri güvenli olup olmadığını nasıl doğrulayacağımı bilmiyorum.


10
Yapamazsın! En azından, işleve void*noktaların neye işaret ettiğini gösteren ikinci bir parametre eklemeniz gerekecektir .
Adrian Mole

4
Yine ikinci bir parametre eklemek gerekirse ... ve sadece de iki ayrı işlevleri yazabilirsiniz func_strve func_structve derleme zamanında tip kontrolüne olsun.
M Oehm

Evet, bu yüzden sadece bir fonksiyonda mümkün olup olmadığını düşünüyordum
localhost

1
Güvenli ve taşınabilir bir şekilde yapamazsınız. Yeterince cesursanız, belleğin ilk baytının karakterler için beklediğiniz gibi görünüp görünmediğini tahmin etmek için sezgisel tarama kullanmaya çalışabilirsiniz, ancak bunu güvenli olarak adlandırmam .
Serge Ballesta

Dize ve yapı işlevleri için yalnızca ortak bir ad istiyorsanız, bir _Genericmakro kullanabilirsiniz . Ayrıca kendini tanımlayan türler de oluşturabilirsiniz, örneğin etiketli sendikalarla , ham bir char *dizeyi geçiremeyeceğiniz anlamına gelir . Tüm bunlar muhtemelen değerinden daha fazla sorun.
M Oehm

Yanıtlar:


12

Tercümesi void*olan
"Sevgili derleyici, bu bir gösterici, bir bu sizin için hiçbir ek bilgi yok.".

Genellikle derleyici sizden (programcı) daha iyi bilir, çünkü daha önce aldığı ve hala hatırladığı ve unutmuş olabileceğiniz bilgiler nedeniyle.
Ancak bu özel durumda, daha iyisini bilirsiniz veya daha iyisini bilmeniz gerekir. Tüm durumlarda void*bilgi başka türlü kullanılabilir, ancak sadece "kim bilir" programcı için. Bunun için programcı, derleyiciye - veya çalışan programa - daha iyi bilgi vermek zorundadır, çünkü void*sahip olduğu avantajlardan biri , bilgilerin çalışma zamanı sırasında değişebilmesidir.
Genellikle bu bilgi fonksiyonlara ek parametreler aracılığıyla, bazen bağlam yoluyla verilir, yani program "bilir" (örneğin, olası her tip için ayrı bir fonksiyon vardır, hangi fonksiyon çağrılırsa tür).

Yani sonunda void*tür bilgisi içermiyor.
Birçok programcı bunu "Tür bilgisini bilmeme gerek yok" olarak yanlış anlıyor.
Ancak bunun tersi doğrudur, kullanım türü bilgisini takip etmek ve programa / derleyiciye uygun şekilde sağlamak için programcının sorumluluğunu void* artırır .


Ek olarak, derleyici aslında işaret edilen veri türünün ne olduğunu bilir. Bu nedenle, bir void*işleve atlarsanız, yanlış türe döküm yaparsanız , verilerin referansını kaldırırsınız ... o zaman tüm tanımlanmamış davranışlar çağrılır.
Lundin

5

void*genel programlama için kullanımdan kaldırılmıştır, günümüzde bunları kullanmanız gereken pek çok durum yoktur. Tehlikeli çünkü var olmayan tip güvenliğe yol açarlar. Ve belirttiğiniz gibi, tür bilgilerini de kaybedersiniz, yani enumile birlikte hantal bazı sürüklemek zorunda kalacaksınız void*.

Bunun yerine _Generictürleri derleme zamanında kontrol edebilen ve tip güvenliği ekleyen C11 kullanmalısınız . Misal:

#include <stdio.h>

typedef struct
{
  int n;
} s_t; // some struct

void func_str (const char* str)
{
  printf("Doing string stuff: %s\n", str);
}

void func_s (const s_t* s)
{
  printf("Doing struct stuff: %d\n", s->n);
}

#define func(x) _Generic((x),              \
  char*: func_str, const char*: func_str,  \
  s_t*:  func_s,   const s_t*:  func_s)(x) \


int main()
{
  char str[] = "I'm a string";
  s_t s = { .n = 123 };

  func(str);
  func(&s); 
}

constDesteklemek istediğiniz her türden nitelikli ( ) sürümler sağlamayı unutmayın .


Arayan yanlış türde geçtiğinde daha iyi derleyici hataları istiyorsanız, statik bir iddia ekleyebilirsiniz:

#define type_check(x) _Static_assert(_Generic((x), \
  char*:   1,  const char*: 1,  \
  s_t*:    1,  const s_t*:  1,  \
  default: 0), #x": incorrect type.")

#define func(x) do{ type_check(x); _Generic((x),     \
  char*: func_str, const char*: func_str,            \
  s_t*:  func_s,   const s_t*:  func_s)(x); }while(0) 

Eğer böyle bir şey denerseniz int x; func(x);derleyici mesajını alırsınız "x: incorrect type".

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.