2012-01-20 14 views
11

Gdy deklarowania wskaźniki w C, są 2 (edycja: 3) wariantachCzy istnieje konwencja dla deklaracji wskaźnika w C?

Wariant A:
int* ptr;

Wariant B:
int *ptr;

Wariant C:
int * ptr;

  • W A, operator indeksu został dołączony do typu.
  • W języku B operator indeksu został dodany do zmiennej.
  • W języku C operator indirectingu swobodnie znajduje się pomiędzy typem a zmienną.

Sposób deklarowania wskaźnika różni się w zależności od rodzaju czytanej dokumentacji. Niektórzy autorzy wydają się preferować pewne warianty, inni używają kilku.

  • Czy mogę przyjąć, że nie ma różnicy w funkcjonalności między różnymi wariantami?
  • Jeśli tak, czy istnieje konwencja, której wariant powinien być używany w języku C?
+3

Nie wiem, dlaczego ludzie głosują, aby to zamknąć.To brzmi jak uzasadnione pytanie do mnie, ale potem hackowałem C tylko od 1980 roku. –

+1

@PeterRowell: jedynym problemem z tego rodzaju banalnym pytaniem jest to, że można znaleźć odpowiedź na to w Internecie przez Google lub dowolne inne wyszukiwanie silnik w ciągu kilku sekund. I każda przyzwoita książka na C też musi to wyjaśnić. Dlaczego ich nie używać? Nie głosowałem, żeby to zamknąć. –

+1

możliwy duplikat [Czy to ważne, gdzie umieszczam gwiazdkę podczas deklarowania wskaźników w C++?] (Http://stackoverflow.com/questions/5449908/does-it-matter-where-i-place-the-asterisk-when -deklaring-pointers-in-c) –

Odpowiedz

11

Nie ma absolutnie żadnej różnicy w funkcjonalności pomiędzy

int* ptr; 

i

int *ptr; 

którego używasz jest do ciebie, istnieje wiele sprzecznych kodowania style do wyboru.

+1

+1. Jest to poprawna odpowiedź w odniesieniu do SO. Bez różnicy, a wybór należy do ciebie. –

+0

Jeśli chcesz uzyskać techniczne, użycie 'int * ptr;' jest również równoważne. Dopóki gwiazdka znajduje się pomiędzy nazwą typu a nazwą zmiennej, białe spacje nie mają znaczenia. – bta

+0

@DanFego: To jest poprawna odpowiedź, jeśli chodzi o kompilator. Istnieją uzasadnione powody stosowania jednej lub drugiej formy, a SO jest doskonałym miejscem do omówienia tych powodów. –

6

Ma to znaczenie tylko wtedy, gdy planujesz zadeklarować wiele zmiennych tego samego typu w tym samym wierszu. Na przykład, jeśli chcesz kilka int wskazówek, trzeba to zrobić:

int *a, *b, *c; 

Stylistycznie choć jest to mylące, gdy jesteś deklarując tylko jedną zmienną. Wiele osób chce zobaczyć ten typ po którym następuje nazwa zmiennej, a typ ma być wskaźnik do int, nie int, więc wolą:

int* a; 
int* b; 
int* c; 

To ostatecznie do ciebie czy wolisz jednej formy nad inny. W ciągu 20 lat programowania C, widziałem około 50% ludzi wybiera jeden nad drugim.

+0

To (dwa powyższe warianty) jest bardzo jasnym sposobem na zajęcie się niezręczną regułą asocjacyjną gwiazdki. Unikam pisania "int * a, b;", "int a, * b;" i "int * a, * b;' ponieważ są one podatne na uwagę, nie dlatego, że nie wiem, co każdy z nich oznacza . Ponadto kompilacja ze wszystkimi włączonymi ostrzeżeniami i utrzymanie kodu "ostrzeżenie-czyszczenie" pomaga uniknąć niepożądanego użycia liczb całkowitych jako wskaźników i na odwrót. –

+0

@ user1118321 Dziękujemy za opublikowanie jednej z niewielu odpowiedzi, które faktycznie rozwiązują problem: deklarowanie więcej niż jednej zmiennej w tym samym wierszu. Jestem całkowicie przeciwny umieszczaniu * typu, ponieważ pokazuje, że programista nie rozumie składni. – doug65536

0

Masz rację, obie oznaczają dokładnie to samo dla kompilatora. Obie instrukcje wygenerują zmienną typu (int *).

Co do którego jest prawidłowa: Puszka robaków! Jest to zwykle temat do dyskusji. Jeśli pracujesz dla firmy lub na OSS, prawdopodobnie najlepiej jest odroczyć się do określonego stylu kodowania. Jeśli go nie ma, zwykle podchodzę do stylu LNT (nie zostawiajmy śladu), który pasowałby do stylu, który został ewidentnie wykorzystany w tej części bazy kodu.

Można argumentować, że czytelnikowi łatwiej jest to zrozumieć. Na przykład int* ptr; stawia * bliżej int który jaśniej komunikuje mówimy o rodzaju (int *) ...

1

w C, spacja nie ma znaczenia, z wyjątkiem gdzie jest to potrzebne do odrębnych tokenów. Oba warianty są poprawne pod względem składniowym.

Wariant 1 kojarzy operator wskaźnika z typem, który jest wystarczająco logiczny. Dla mnie to wystarczyłoby, gdyby nie powód, dla którego Wariant 2 miałby sens.

Wariant 2 jest zgodny ze strukturą deklaracji C. W gramatyce języka C operator wskaźnika należy do deklaratora (to znaczy do nazwy), a nie do typu. Ma to znaczenie przy zadeklarowaniu wielu zmiennych w tej samej deklaracji. Istnieje również wiele bardziej ezoterycznych przypadków, w których ma to znaczenie.

Tak więc, dla mnie Wariant 2 jest bardziej spójny z C. Ale każdy z wariantów jest zdolny do obrony, a oba warianty są konwencjonalne.

4

Oba oznaczają to samo, co inne osoby. Czeka cię jednak pułapka. Rozważmy następujący kod:

int* a, b; 

Można by pomyśleć, że to uznany wskaźników do int. Nie, ale inaczej. W rzeczywistości a jest int*, ale b jest int. Jest to jeden z powodów, dla których wielu programistów C woli umieszczać * obok zmiennej zamiast typu. Kiedy napisane tak:

int *a, b; 

jesteś mniej prawdopodobne, aby być wprowadzony w błąd co do tego, co a i b są.

Powiedziawszy to wszystko, wiele standardów kodowania domaga się deklarowania nie więcej niż jednej zmiennej na linię, tj.

int* a; 
int b; 

Jeśli podążacie za jedną zmienną na regułę liniową, to zdecydowanie nie ma miejsca na pomyłki.

4
T *a; 

jest preferowanym C styl sposób zadeklarować wskaźnik do T stosowany w Kernighana & książki Ritchiego o C

T* a; 

jest preferowanym C++ styl droga do wskaźnika deklarują T stosowany w książce Stroustrupa o C++.

Oba oznaczenia są równoważne.

+1

+1 za odwołanie się do organu ;-) –

12

Coś nikt nie wspomniał, że

int *ptr; 

odpowiada bardziej do gramatyki języka.

  • int *ptr; to zgłoszenie , który składa się z:
    • zgłoszenie-specyfikatorint, a następnie
    • declarator, *ptr.

(który faktycznie pomija szereg kroków, ale robi się podstawowe pojęcia w poprzek.)

Ponieważ deklaracja następująco wykorzystania, oznacza to, że *ptr jest typu int. Wynika z tego, że ptr jest typu int*.

Można by argumentować, że to sprawia, że ​​lepiej niż

int* ptr; 

z tego samego powodu, że

x = y+z; 

jest lepsza niż

x=y + z; 

Oczywiście, że może napisać

int* ptr; 

i odczytać go jako "ptr jest typu int*". I wielu programistów robi dokładnie to i dobrze sobie radzi (zwykle jest preferowanym stylem w C++). Kompilator nie dba o to, w jaki sposób to robisz, a każdy, kto czyta twój kod, nie powinien mieć problemów ze zrozumieniem go w żaden sposób.

Ale cokolwiek rozstaw wybierzesz, musisz zrozumieć, co int *ptr; naprawdę oznacza, że ​​gdy widzisz

int *ptr, i; 

w czyimś kodzie (jak to nieuchronnie będzie), będziesz od razu zrozumieć, że ptr jest wskaźnik i i to int.

Jeśli pracujesz z innymi programistami przy projekcie, powinieneś postępować zgodnie z obowiązującą konwencją zawartą w standardach kodowania lub, jeśli takowe nie istnieje, sposobem, w jaki kod został już napisany. Osobiście wolę od int *ptr; do int* ptr;, ale używanie kombinacji obu stylów jest o wiele gorsze niż używanie jednego z nich konsekwentnie.

2

Deklaracje C opierają się na typach wyrażeń , a nie obiektach.

Jeśli masz wskaźnik do int nazwie pi i chcesz uzyskać dostęp wartość całkowitą, która wskazuje na to, masz do nieprawidłowego wskaźnika, na przykład:

x = *pi; 
printf("%d", *pi); 
*pi = 1 + 2; 

etc.Rodzaj ekspresji*pijest int: zatem deklaracja powinna odczytywać jako

int *pi; 

Teraz załóżmy miał tablicę wskaźników do char; aby dostać się do dowolnego znaku, należy do pierwszego indeksu do tablicy, a następnie nieprawidłowego wyniku:

c = *pc[i]; 
if (*pc[j] == 'a') {...} 

itd. Ponownie, rodzaj ekspresji*pc[i] jest char na , więc deklaracja brzmi

char *pc[N]; 

Zarówno *pi i *pc[N] są znane jako declarators i określ dodatkowe informacje o typie nie podane przez specyfikatora typu. IOW, array-ness i wskaźnik pc są określone jako część deklaratora, natomiast char -ness jest określony przez specyfikator typu.

Co do kwestii, które jest styl jest właściwa ...

Ani jeden jest „prawo”, ale ja (i wielu innych programistów C) wolą pisać T *p w przeciwieństwie do T* p, ponieważ ściślej odzwierciedla gramatykę języka (* jest częścią deklaratora) i pomaga uniknąć nieporozumień podczas deklarowania wielu elementów. Widziałem daleko zbyt wiele przykładów osób piszących T* a, b; i oczekujących, że b będzie wskaźnikiem.

Zwykłą reakcją na tę krytykę jest "nie zadeklaruj więcej niż jednego produktu w wierszu". Moja odpowiedź na tę odpowiedź brzmi: "napisz poprawnie swoich deklaratorów i nie będziesz miał żadnych problemów".

Jest inna szkoła myślenia wśród wielu programistów C++, którzy preferują styl T* p, i muszę powiedzieć, że istnieje kilka przypadków (ograniczone do C++), gdzie może uczynić kod bardziej czytelnym.

Jednak działa to tylko w przypadku prostych wskaźników do T: paradygmat ulega szybkiemu zerwaniu, gdy zaczynasz radzić sobie z tablicami wskaźników lub wskaźników do tablic lub wskaźników do funkcji, lub wskaźników do tablic wskaźników do funkcji itp. Chodzi o to, że napisanie czegoś takiego, jak

T* (*(*p)[N])(); // p is a pointer to an array of pointers to functions 
       // returning pointers to T. 

tylko wskazuje mylić myśli. Chociaż, jeśli naprawdę naprawdę naprawdę czujesz, że musi śledzić T* p paradygmatu, zawsze można stworzyć serię typedefs:

EDIT

spróbujmy jeszcze raz:

typedef T* TPtr;       // pointer to T 
typedef TPtr TPtrFunc();     // function returning pointer to T 
typedef TPtrFunc* TPtrFuncPtr;    // pointer to function returning 
              // pointer to T 
typedef TPtrFuncPtr TPtrFuncPtrArray[N]; // N-element array of pointer to function 
              // returning pointer to T 

TPtrFuncPtrArray* p; 

Z miłości do Boga, nie rób tego.

Powiązane problemy