Co powinien wiedzieć programista C? [Zamknięte]

12

Jakie są niektóre koncepcje / techniki / funkcje językowe, o których każdy przyzwoity programista C powinien wiedzieć / być świadomym (wyłącz ogólną inżynierię oprogramowania i podobne i skupiaj się tylko na specyficznych rzeczach C). Chciałbym wiedzieć, żebym mógł uzupełnić niektóre możliwe luki w mojej wiedzy o C.

Anto
źródło
9
Zacznij od pytań C dotyczących przepełnienia stosu i sprawdź, czy jest coś, czego nie wiesz.
chrisaycock
3
Programista AC prawdopodobnie powinien to wiedzieć2 + 2 = 4
Edward Strange
21
Powinni wiedzieć o sklepie, który sprzedaje obuwie kuloodporne.
Adam Crossland,
1
Istnieją setki książek na ten temat. Twoje pytanie jest naprawdę dość niejasne. Musisz być bardziej konkretny, aby uzyskać przyzwoite odpowiedzi, które nie są tylko listą rzeczy. Biorąc pod uwagę, że odpowiedzi były tak dalekie od tego pytania, pomyślałbym, że należy je przerobić lub zamknąć.
Walter
2
Inny język programowania?
Muhammad Alkarouri

Odpowiedzi:

19

Specyficzny dla C? Oprócz standardowych konstrukcji wspólnych dla większości języków proceduralnych, muszę powiedzieć:

  • (ab) przy użyciu preprocesora
  • linker vs kompilator
  • Wskaźniki Wskaźniki Wskaźniki!
  • Jak tablice są wskaźnikami, są tablicami
  • Jak działają ciągi C i jak są one również wskaźnikami i tablicami
  • Jak złe użycie łańcucha C może spowodować przepełnienie bufora
  • Jak rzucić cokolwiek na cokolwiek (to wszystko to tylko 1 i 0 w końcu :))
  • Ręczne zarządzanie pamięcią malloc / free
  • Stack vs Heap
  • Alias ​​wskaźnika, (dlaczego jest nielegalny w C99)
  • Myślenie o rozwoju w kategoriach modułów (plików .h / .c) z zestawem publicznie dostępnych funkcji zamiast ściśle klas
  • Związki
  • Dlaczego sprintf może zdmuchnąć twoją stopę
  • Wskaźniki funkcji
Doug T.
źródło
Dodałbym do listy „przepełnienia bufora”.
Aidan Cully,
@Aidan, dobry połów. Dodany.
Doug T.,
2
Jak tablice C i wskaźniki nie są takie same: books.google.ca/…
Matthieu
wskaźniki powinny być powtórzone co najmniej 3 razy więcej
Gaurav
8

Zrozumienie wskaźników, a zrozumiesz komputery.

PP.
źródło
12
Nie, po prostu dostaniesz złudzenie, że rozumiesz komputery.
Job
5

Oprócz doskonałej odpowiedzi pythagras,

jak pisać (lub przynajmniej czytać) skomplikowane deklaracje, takie jak char (*(*funcs[4])())[10]

funcs jest tablicą [4] wskaźników do funkcji zwracającej wskaźnik do tablicy [10] char

tcrosley
źródło
1
Jeśli robi się tak skomplikowany, może to należy do komentarza?
Job
7
może powinien nauczyć się, jak unikać takiego pisania?
FabianB
3
  1. Reguły promocji na liczby całkowite
  2. Zainicjuj wszystko do znanej wartości
  3. GOTO nie jest zły, szczególnie gdy jest używany do obsługi wyjątków / awarii
  4. malloc i / lub calloc mogą zwracać NULL ... upewnij się, że wartości czeku zwracają
  5. Częste przydziały małej pamięci mogą powodować fragmentację sterty.
  6. Wskaźnik arytmetyczny
  7. Maski bitowe są twoim przyjacielem
  8. x >> 1 jest równoważne x / 2 dla liczb całkowitych bez znaku
Pemda
źródło
+1 za to, że GOTO nie jest zły :)
zvrba
2

Programista AC powinien znać ... inne języki! ;-) Zawsze dobrze jest znać pojęcia z innych języków różnych paradygmatów, takich jak OOP, programowanie funkcjonalne i tak dalej.

Co więcej, spojrzenie na zaciemniony konkurs programistyczny jest zabawny i, co ciekawe, również dobre doświadczenie.

PhiLho
źródło
2

Wspomniałem o „przepełnieniu bufora” w komentarzu do odpowiedzi Pythagrasa, prawdopodobnie powinienem wyjaśnić, co miałem na myśli. W języku C nie wystarczy wiedzieć, że bezpośrednia praca z pamięcią jest niebezpieczna - należy również zrozumieć dokładne sposoby jej niebezpieczeństwa. Naprawdę nie podoba mi się metafora „strzelania sobie w stopę” dla wszystkich tych przypadków - przez większość czasu to nie ty pociągasz za spust, ale często jest to aktor o interesach sprzecznych z twoim i / lub użytkownikami ” .

Na przykład w architekturze ze stosem malejącym (najpopularniejsze architektury pasują do tego rachunku - ogólnie x86 i ARM), gdy wywołasz funkcję, adres zwrotny funkcji zostanie umieszczony na stosie po zmiennych lokalnych zdefiniowanych w parametrze treść funkcji. Jeśli więc zadeklarujesz bufor jako zmienną lokalną i udostępnisz tę zmienną światu zewnętrznemu bez sprawdzania przepełnienia bufora, to tak:

void myFn(void) {
    char buf[256];
    gets(buf);
}

zewnętrzny użytkownik może wysłać ci ciąg znaków, który zastępuje adres zwrotny ze stosu - w zasadzie może zmienić pomysł programu na graf wywołań, który prowadzi do bieżącej funkcji. Użytkownik podaje więc ciąg znaków, który jest binarną reprezentacją kodu wykonywalnego dla twojej architektury, wystarczającą dopełnieniem, aby przepełnić stos myFn, oraz dodatkowe dane, aby zastąpić adres zwrotny w myFncelu wskazania kodu, który ci dał. Jeśli tak się stanie, to kiedy myFnzwykle zwróci kontrolę nad swoim abonentem wywołującym, zamiast tego rozgałęzi się do kodu dostarczonego przez złośliwego użytkownika. Jeśli napiszesz kod C (lub C ++), który może być narażony na zaufanie niezaufanych użytkowników, musisz zrozumieć ten wektor ataku. Powinieneś zrozumieć, dlaczego przepełnienie bufora w stosunku do stosu jest często (ale nie zawsze) łatwiejsze do wykorzystania niż w przypadku stosu, i powinieneś zrozumieć, w jaki sposób układana jest pamięć w stosie (niekoniecznie zbyt szczegółowo, ale pomysł, że w danym malloc()regionie znajdują się otaczające go struktury kontrolne, może pomóc zrozumieć, dlaczego twój program ulega awarii w innym malloc()lub w free()).

C udostępnia ci szczegółowe informacje o tym, jak działa twój komputer, i daje ci większą bezpośrednią kontrolę nad twoim komputerem, niż jakikolwiek inny język edytowany przez użytkowników w powszechnym użyciu. Z wielką mocą wiąże się wielka odpowiedzialność - tak naprawdę musisz zrozumieć te szczegóły niskiego poziomu, aby bezpiecznie i skutecznie pracować z C.

Aidan Cully
źródło
0

Oprócz innych dobrych odpowiedzi chciałbym dodać do listy techniki programowania obronnego .

Np. Używanie stwierdzeń na początku / na końcu funkcji do weryfikacji kontraktu.

AndersK
źródło