İnt (*) (int *) = 5'in (veya herhangi bir tam sayı değerinin) anlamı


88

Bunu çözemiyorum:

int main() {
    int (*) (int *) = 5;
    return 0;
}

Yukarıdaki atama, g ++ c ++ 11 ile derlenir. Bunun int (*) (int *)bir (int *)argüman olarak kabul eden ve bir int döndüren bir işleve işaret eden bir işaretçi olduğunu biliyorum , ancak onu 5'e nasıl eşitleyebileceğinizi anlamıyorum. İlk başta bunun sürekli olarak 5 döndüren bir işlev olduğunu düşündüm (son öğrendiğimden F #, muhtemelen, haha), sonra kısaca, işlev göstericisinin bellek konumu 5'i gösterdiğini düşündüm, ancak bu açıkça çalışmıyor ve onaltılık değerler de yapmıyor.

Bunun işlevin bir int döndürmesi ve int atamanın tamam (bir şekilde) olmasından kaynaklandığını düşünerek, şunu da denedim:

int * (*) (int *) = my_ptr

my_ptrtip neredeint * , int türündeki ilk durumda olduğu gibi bu ikinci işlev göstericisiyle aynı tür. Bu derlemez. Bunun yerine 5 veya herhangi bir int değeri atamak, my_ptrbu işlev göstericisi için de derlenmez.

Öyleyse görev ne anlama geliyor?

Güncelleme 1

En iyi yanıtta gösterildiği gibi bunun bir hata olduğuna dair teyit aldık. Ancak, yine de gerçekte neyi bilinmemektedir olur sen işlev işaretçisi atamak bu değere, ya da ne görevle olur için. Bununla ilgili herhangi bir (iyi) açıklama çok takdir edilecektir! Sorunla ilgili daha fazla netlik için lütfen aşağıdaki düzenlemelere bakın.

Düzenle 1

Gcc 4.8.2 sürümünü kullanıyorum (Ubuntu 4.8.2'de)

Düzenle 2

Aslında, onu derleyicimde işe yarayan herhangi bir şeye eşitlemek. Bunu bir std :: string değişkenine veya double döndüren bir işlev adına eşitlemek bile işe yarar.

Düzenleme 2.1

İlginç bir şekilde, işaretçi olmayan bir veri türünü döndüren herhangi bir işlevin işlev göstericisi yapmak, derlemesine izin verir,

std::string (*) () = 5.6;

Ancak işlev işaretçisi, bir işaretçi döndüren bir işleve gelir gelmez, derleme yapmaz, örneğin

some_data_type ** (*) () = any_value;

3
Hmm ... doğru görünmüyor ve clang bunu kabul etmiyor. Bir gcc uzantısı (veya hata) olabilir.
Wintermute

4
g ++ error: expected identifier or '(' before ')' token
derliyor

3
@ 0x499602D Kodun işaretçiye bir ad vermediğini unutmayın. İle int *x = 5bunu adında x. Onunla int * (*x) (int *) = 5derlenmeyecek. (C kodu olarak derlense de).
hayır

5
Azaltılmış test senaryosu: int(*) = 5;veint(*);
Johannes Schaub - litb

Yanıtlar:


60

Bu g ++ 'da bir hata.

 int (*) (int *) 

bir tür adıdır.

C ++ 'da, tanımlayıcı olmayan bir tür adıyla bir bildiriminiz olamaz.

Yani bu, g ++ ile derlenir.

 int (*) (int *) = 5;

ve bu da derler:

 int (*) (int *);

ancak ikisi de geçersiz beyanlardır.

DÜZENLE :

TC , yorumlarda bugzilla bug 60680'den benzer bir test senaryosundan bahsediyor, ancak henüz onaylanmadı . Hata bugzilla'da onaylandı.

DÜZENLEME2 :

Yukarıdaki iki bildirim dosya kapsamında olduğunda, g ++ doğru bir şekilde bir tanılama yayınlar (blok kapsamında tanılamayı gerçekleştiremez).

DÜZENLEME3 :

Kontrol ettim ve sorunu g ++ sürüm 4'ün (4.9.2) en son sürümünde, en son yayın öncesi sürüm 5'de (5.0.1 20150412) ve en son deneysel sürüm 6'da (6.0.0 20150412) yeniden oluşturabilirim.


5
MSVC, düzenlenmiş yayınlanan kodu şu şekilde reddettierror C2059: syntax error : ')'
Weather Vane

Bir tür adı ise, neden 'int (*) (int *) int_func;' iş?
Konrad

1
GCC bugzilla için "YENİ" onaylanmış bir hatadır. (Onaylanmamış hatalar "ONAYLANMAMIŞTIR").
TC

4
@KonradKapp: int (*int_func)(int *); Adlandırılmış bir işlev göstericisinin hangisi olduğunu söylerseniz iyi çalışır int_func.
Edward

3
@KonradKapp C ++, tanımlayıcıyı yerleştirmek için infix gösterimini kullanır; aynı nedenle öyle int x[5];değilint[5] x;
MM

28

C ++ geçerli değil. Unutmayın ki, özel derleyiciniz derlemek için olduğu için onu geçerli kılmaz. Derleyiciler, tüm karmaşık yazılımlar gibi bazen hatalara sahiptir ve bu bir gibi görünür.

Aksine clang++şikayetler:

funnycast.cpp:3:11: error: expected expression
    int (*) (int *) = 5;
          ^
funnycast.cpp:3:18: error: expected '(' for function-style cast or type construction
    int (*) (int *) = 5;
             ~~~ ^
funnycast.cpp:3:19: error: expected expression
    int (*) (int *) = 5;
                  ^
3 errors generated.

Soruna neden olan satır geçerli C ++ olmadığı için bu beklenen davranıştır. Bir atama olduğunu iddia eder (nedeniyle =) ancak tanımlayıcı içermez.


9

Diğer yanıtların da işaret ettiği gibi, bu bir hata

int (*) (int *) = 5;

derler. Bir anlamı olması beklenen bu ifadeye makul bir yaklaşım şöyledir:

int (*proc)(int*) = (int (*)(int*))(5);

Şimdi proc, 5adresin bir alan int*ve bir döndüren bir işlevin temel adresi olmasını bekleyen bir işaretçi işlevidir int.

Bazı mikro denetleyicilerde / mikroişlemcilerde 5 geçerli bir kod adresi olabilir ve bu tür bir işlevi orada bulmak mümkün olabilir.

Genel amaçlı bilgisayarların çoğunda, işaretçi erişimlerini 0-1023yakalamak için belleğin ilk sayfası ( 4K sayfalar için adresler ) bilerek geçersizdir (eşlenmemiş) null.

Bu nedenle, davranış platforma bağlı olsa da *proc, başlatıldığında bir sayfa hatasının oluşması makul bir şekilde beklenebilir (örneğin, (*proc)(&v)). Çağrılmadan önce *procolağandışı bir şey olmaz.

Dinamik bir bağlayıcı yazmadığınız sürece, neredeyse kesinlikle adresleri sayısal olarak hesaplamamalısınız ve bunları işleve işaret eden değişkenlere atamalısınız.


2
/usr/lib/gcc/x86_64-pc-cygwin/4.9.2/cc1plus.exe -da so.cpp

Bu komut satırı çok sayıda ara dosya oluşturur. Bunlardan ilki so.cpp.170r.expandşöyle diyor:

...
int main() ()
{
  int D.2229;
  int _1;

;;   basic block 2, loop depth 0
;;    pred:       ENTRY
  _1 = 0;
;;    succ:       3

;;   basic block 3, loop depth 0
;;    pred:       2
<L0>:
  return _1;
;;    succ:       EXIT

}
...

Bu hala tam olarak ne olduğunu cevaplamıyor, ancak doğru yönde atılmış bir adım olmalı.


İlginç. Bu ara dosyaların amacı nedir?
Konrad

@KonradKapp İnsan kodundan makine kodu üretmek oldukça karmaşık bir süreçtir (özellikle derleyicinizin çıktısını optimize etmesini istiyorsanız). Derleme çok karmaşık olduğu için tek adımda yapılmaz, çoğu derleyicide bir tür Ara Temsil (IR) vardır.
11684

2
Bir IR'ye sahip olmanın bir başka nedeni de, iyi tanımlanmış bir IR'ye sahipseniz, derleyicinizin ön ucunu ve arka ucunu ayırabilmenizdir. (Örneğin, ön uç C'yi IR'nize derler, arka uç IR'yi Intel makine koduna derler. Şimdi, ARM desteği eklemek istiyorsanız yalnızca ikinci bir arka uca ihtiyacınız vardır. Ve Go'yu derlemek istiyorsanız, yalnızca bir ikinci ön uç ve bunun da
ötesinde

@ 11684 Tamam, mantıklı. Çok ilginç. Yine de Roland'ın bu cevapta hangi dili verdiğini belirleyemedim ... C ile karıştırılmış bir tür montaj gibi görünüyor
Konrad

IR'nin yazdırılabilir olması gerekmez; Gcc'nin ne kullandığı hakkında hiçbir fikrim yok, bu yalnızca yazdırılabilir bir sunum olabilir @KonradKapp
11684
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.