2009-02-12 21 views
14

W języku programowania C rozumiem, że zmienne mogą być zdefiniowane tylko na początku bloku kodu, a zmienna będzie miała zakres bloku, w którym została zadeklarowana. Z tą myślą zastanawiałem się, czy uważa się złą praktyką sztucznie utworzyć nowy zakres, jak w poniższym przykładzie:Czy (PRAWDA) dobry pomysł w C?

void foo() 
{ 
    ... Do some stuff ... 

    if(TRUE) 
    { 
     char a; 
     int b; 

     ... Do some more stuff ... 
    } 

    ... Do even more stuff ... 
} 

Zakładając PRAWDA jest ustawiony na 1 w definicji makra, to kod ten należy uznać za „dobry kod”, czy też zrobić programiści doświadczeni warować na samą myśl o tym?

Dzięki za twój wkład!

EDYCJA: W odpowiedzi na niektóre z odpowiedzi, kod, nad którym pracuję, musi działać z dość starymi, starszymi systemami. Chociaż dobrze byłoby działać na założeniu C99, nie możemy zagwarantować, że będą go mieli.

+0

afaik, {} ma własny zakres sine ansi C (to jest około 1990) – George

+0

Typowym przykładem tego jest debugowanie, w którym można łatwo przełączać się pomiędzy (42) i (0) zamiast komentować. – ypnos

+0

Twój tytuł nie opisuje w ogóle tego pytania. Wydaje się, że pytasz, czy dobrą praktyką jest definiowanie PRAWDA. – BobbyShaftoe

Odpowiedz

49

Nie potrzebujesz nawet instrukcji if. Możesz tworzyć bloki za pomocą {}

Prawdopodobnie powinna to być jednak osobna funkcja.

Przykład tutaj:

#include <stdio.h> 

int 
main(int argc, char **argv) { 
    int i = 0; 
    { 
     int i = 10; 
     printf("%d\n", i); 
    } 
    printf("%d\n", i); 
} 
+0

Czy jest to kiedykolwiek używane w kodzie produkcyjnym? Myślę, że chcę mieć dostęp do wszystkich zmiennych w istniejącej funkcji, ale kilka nowych zmiennych dotyczy tylko niewielkiej sekcji. Funkcja oznaczałaby, że musiałbym przekazać całą masę zmiennych i dodanie zmiennych do głównej ... – Tim

+0

... funkcja zaśmiecałaby istniejące zmienne funkcji – Tim

+0

moja firma używa tego w znacznym stopniu. Kiedyś zacząłem tu pracować, ale naprawdę mi się to podobało, ale teraz to lubię. Nadal nie podoba mi się sposób, w jaki go używamy, który zwykle polega na rozbijaniu fragmentów funkcji 1000 linii, które powinny być ich własną funkcją ... – rmeador

7

Prawdopodobnie chcesz utworzyć nową funkcję dla tego zakresu.
Jeśli naprawdę musi mieć swój własny zakres, to prawdopodobnie jest to osobna funkcja logiczna.

+2

Niekoniecznie. Często spotkałem się z koniecznością użycia pewnej wysoce lokalnej zmiennej (z ładną nazwą mnemoniczną), aby utrzymać pewną pośrednią wartość tylko dla kilku linii. Używając zakresu zagnieżdżonego, wyjaśniasz jego zamierzone (ograniczone) użycie. –

3

Nie nazwałbym się doświadczonym, ale jestem trochę skulony.

Mój problem polega na tym, że instrukcja if sprawi, że ktoś uwierzy, że coś jest aktualnie analizowane ... ale w czasie wykonywania makro jest prawdziwe lub fałszywe, nie ma zmiany tego, że jest czymś innym. Powinieneś albo podać kod, albo nie.

Jeśli to, co masz na myśli, aby zrobić coś jak #ifdef DEBUG to należy zrobić, aby wskazać, że jest to czytnik kodu debug ...

+0

Makro jest analizowane w czasie kompilacji, a nie w czasie wykonywania. –

2

Nie sądzę, trzeba if (true) część.

Tylko {} są wymagane do zmiany zakresu zmiennych.

2

Moja odpowiedź jest następująca:

To sprawia, że ​​programiści doświadczeni warować na samą myśl o tym.

6

Ponieważ możesz po prostu utworzyć blok zasięgu bez znaku, jeśli, to jest lepszy pomysł.

void foo() { 
    ... Do some stuff ... 
    { 
     char a; 
     int b; 
     ... Do some more stuff ... 
    } 
    ... Do even more stuff ... 
} 
16

O ile wiem, można utworzyć zakres bez.

używać tylko szelki takie jak ten:

{ 
    int x; 

} 

A ja odradzam

if (TRUE) 

ponieważ utrudnia czytelność.

+6

zwłaszcza, jeśli #define TRUE 0 –

4

można usunąć

if(TRUE) 

i po prostu zostawić szelki, które same określają nową składniowej zablokuj - do compound statement.

Jest to zdecydowanie czystsze niż fałsz, jeśli wcześniej, ale nadal możesz zadać sobie pytanie, dlaczego chcesz utworzyć nowy blok - czy byłoby lepiej zdefiniować podprogram?

5

Po pierwsze, nowy blok nie musi być blokiem if. Może to być po prostu fragment kodu otoczony szelek, tak:

void foo() { 
... Do some stuff ... 

{ 
    char a; 
    int b; 

    ... Do some more stuff ... 
} 

... Do even more stuff ... 
} 

Po drugie, w każdym nowoczesnym kompilator C, który jest zgodny ze standardem C (myślę, C99), można deklarować zmienne w dowolnym miejscu na bloku, więc nie musisz w ogóle tworzyć nowego bloku.

3

zostawiając drzwi otwarte dla niektórych ludzi twórczych:

#define TRUE 0 
#define FALSE 1 

Wystarczy użyć szelki zadeklarować zakres.

1

C99 pozwala zadeklarować zmienne prawie w dowolnym miejscu. Powstrzymaj się jednak od tego bez ważnego powodu. Spróbuj najpierw podzielić swoją funkcję na mniejsze (prawdopodobnie inline) funkcje.

Jedynym miejscem, w którym takie coś może mieć sens, jest sytuacja, gdy masz zmienną zainicjowaną w środku funkcji, np. podobne do tworzenia obiektu w C++.

+0

Nie jestem pewien, dlaczego mówisz, aby powstrzymać się od tego. Jeśli potrzebuję prostej int lub char, wydaje się, że czystsze jest deklarowanie jej blisko kodu, który jej użyje, zamiast wysyłania jej na szczyt funkcji. Co robię, robiąc to? – rtperson

+0

Deklarowanie zmiennych w punkcie pierwszego użycia jest uważane za dobrą praktykę w C++. Dlaczego nie w C99? –

+0

@David Thornley: C zwykle pozwala programistce pisać bardzo długie funkcje, bardziej prawdopodobne niż C++ z powodu braku funkcji językowych OOP. Posiadanie wielu zmiennych na początku funkcji jest dobrym znakiem, że jest zbyt długi. Praktyka może być nawykiem. Ale deklarowanie tuż przed pierwszym użyciem może być uzasadnione. –

1

Myślę, że pracujesz z pewnymi nieaktualnymi założeniami. Od kilku miesięcy koduję proste C używając GCC i nie musisz deklarować zmiennych na początku bloku, mimo że druga edycja K & R mówi, że musisz. Można zadeklarować zmienną w dowolnym miejscu, podobnie jak to niezbyt użyteczny przykład:

char* palstring; 
palstring = malloc(LARGEST_STRING); 
memset(palstring, 0, sizeof palstring); 
fgets(palstring, LARGEST_STRING, fin); 

char* cur = palstring; 
char letter; 
letter = *cur; 

Więc nie ma potrzeby, aby robić to, co sugerujesz. Język się przeniósł.

Innym dobrym dodatkiem do języka C są tablice o zmiennej długości, które pozwalają przekazać tablicę do funkcji wraz z jej rozmiarem. W dawnych czasach wszystko, co mogłeś zrobić, to przekazać wskaźnik.

+0

Ostrożne tablice długości gcc nie są standardem C99 –

+0

Ah, dobrze wiedzieć. Dziękuję Ci. Używam go głównie do samodzielnego robienia zdjęć, więc nie martwię się zbytnio, ale jeśli będę musiał go używać profesjonalnie, będę ci winien piwo. :) – rtperson

4

Jak już powiedzieliśmy w wielu odpowiedziach, nie potrzebujesz rzeczy "jeśli". Po prostu utwórz goły blok. Ale chcę dostać w innym punkcie. W języku C można tworzyć deklaracje zmiennych w dowolnym miejscu bloku, nie tylko na początku. W C89 masz to ograniczenie. Począwszy od C99 (to już 10 lat), nie masz już tego ograniczenia, chociaż niektóre kompilatory i tak będą jęczeć. GCC nie będzie jednak, jeśli powiesz mu, aby używał najbardziej "ostatniego" C Standardu z opcją -std = c99.

Ponieważ w dalszym ciągu istnieją kompilatory, które domyślnie narzekają, nie chciałbym jednak mieszać deklaracji i kodu. Nadal składałem deklaracje na początku bloków ze względu na kompatybilność.

+0

Tak, myślę, że ta zła praktyka w C. Jeśli skompilujesz z -Wall -ansi -pedantic, otrzymasz ostrzeżenia. Moja zasada brzmi: jeśli te flagi nie są czyste, generalnie jest źle. – BobbyShaftoe

+0

BobbyShaftoe. cóż, to jest ważna kwestia. ale nie sądzę, że to zła praktyka. Unikam używania -Werror właśnie dlatego, że czasami kompilator może ostrzec błędnie. to wtedy, jeśli ostrzega o "... {...} ...", co jest odpowiednio komentowane, jest dla mnie fałszywie pozytywne. –

6

Należy zauważyć, że w C99 dopuszczalne jest deklarowanie lokalnych zmiennych w środku bloków.

C99 to wersja standardu C z 1999 roku; obsługuje go większość nowoczesnych kompilatorów języka C.

1

Zakładając, że używasz starego kompilatora (tak jak ja, to dla starego sprzętu), pomijasz jeśli (PRAWDA), jak sugerowali inni, i że masz naprawdę OGROMNĄ funkcję (nie powinieneś mieć w pierwsze miejsce), wtedy myślę, że jest w porządku. Zrobiłem to, ale nie czułem się dobrze ...

1

Podobno jestem w mniejszości, ale uważam, że "tylko aparaty ortodontyczne" są znacznie trudniejsze do odczytania, ponieważ odbiegają od typowego schematu. Na (co prawda rzadko) okazjach gdzie chcę scoped blok bez definiowania inną funkcję, wolę zawierać „jeśli”, ale bez makr i wraz z komentarzem, aby wyjaśnić dlaczego:

if(1) // just to establish scope 
{ 
    // do stuff here 
} 
2

Wystarczy zdefiniować zmienne na początku bloku lub użyj innej funkcji. Dodanie sztucznego zakresu za pomocą pustych {} s lub dowolnej alternatywy nie jest dobrą praktyką.

Powiązane problemy