główna strona  C
polubić nie sposób
porzucić niepodobna
 
Kiedy próbowałem zapoznać się w praktyce z C, zaprzyjaźnieni programiści wskazali mi przeglądarkę plików tekstowych SEE. To fonetyczne nieporozumienie typowe dla języka angielskiego, nieodmiennie śmieszy mnie do dziś.
prehistoria
Zakładowy dział informatyki lat 80-tych koncentrował się zwykle na przetwarzaniu danych, a dominującym językiem był Clipper, wyposażony w wygodne funkcje do manipulowania danymi typu DBF. Nauczyłem się całkiem biegle posługiwać tym narzędziem, ale dziś nie zaliczam go do swych fascynacji, ani nawet nie przyznaję się do tej umiejętności w obawie, że ktoś mógłby zechcieć ją wykorzystać. Clipper nie był zbyt wydajny w wyświetlaniu informacji, a na dodatek dysponowaliśmy bardzo kiepskimi komputerami. To pchnęło mnie w objęcia języka C, którego moduły łączyły się bezboleśnie z programami w Clipperze. Dzięki temu powstała biblioteka funkcji grzebiących bezpośrednio w pamięci karty graficznej i wyświetlających dane z prędkością światła. Z dzisiejszego punktu widzenia jest to umiejętność całkowicie nieprzydatna, ale zabawa w optymalizację kodu była bardzo pouczająca.
za jakie grzechy?
Trudno znaleźć język programowania łatwiejszy... do popełniania błędów. Swą niezwykłą popularność zawdzięcza prawdopodobnie temu, że stał się podstawowym narzędziem oprogramowania w systemie UNIX, a w ślad za nim w Linuksie. Stał się tak popularny, że dziś praktycznie nie ma systemu, dla którego nie znaleźlibyśmy (przeważnie darmowego) kompilatora. Wartym zauważenia atutem C jest bogaty wybór funkcji bibliotecznych.
Choć nie grzeszy urodą i ma wiele mankamentów, C trwale wrósł w historię i teraźniejszość informatyki, dał podwaliny wielu współczesnym językom, jak Perl, Java czy .NET - nie ma przed nim ucieczki.
kiedy używam C?
O tym, czy napisaliśmy program w C czy w C++ decyduje głównie wykorzystanie (bądź nie) elementów programowania obiektowego. Ale i tak zawsze można użyć kompilatora C++ do skompilowania takiego programu. Dla mnie trzymanie się czystego C w przypadkach, gdy złożoność zagadnienia na to pozwala, jest bardziej kwestią staromodnego przywiązania do prostoty niż oczekiwaniem jakichś wydumanych korzyści. Program skompiluje się szybciej, a jego kod binarny będzie z pewnością nieco krótszy, choć nie w stopniu, który by można oceniać w kategoriach marnotrawstwa pamięci masowej. Po prostu lubię używać minimalnych środków wystarczających do osiągnięcia założonego celu.
oprogramowanie portu szeregowego
Ten przykład pokazuje, jak można wykorzystać port szeregowy komputera w systemie Linux w charakterze prostego urządzenia WE/WY. Uwypukla atuty języka C: współużywane deklaracje zawarte w pliku nagłówkowym, wygodny dostęp do rejestrów sprzętowych komputera, zwarty, efektywny kod.
Uwaga: programowy dostęp do portu szeregowego wymaga uprawnień administratora.
Plik nagłówkowy ser.h zawiera definicje bitów w rejestrach urządzenia i kojarzy je ze stykami gniazda. Rysunek w stylu ASCII-art pokazuje rozmieszczenie końcówek w gnieździe, tak jak je widać na tylnej ścianie komputera.
# ser.h
# 
#include <stdlib.h>   // exit
#include <sys/io.h>   // read, write I/O ports
/*     male
   +-----------+
 1 \ o o o o o /
    \ o o o o / 9
     +-------+
*/
#define PORTS   { 0x3F8, 0x2F8, 0x3E8, 0x2E8 }
#define MCR     0x04  // Modem Control Register
#define MSR     0x06  // Modem Status Register

#define DCD     0x80  // <- 1 Data Carrier Detect (MSR)
//      RXD              <- 2 Receive Data
//      TXD              -> 3 Transmit Data
#define DTR     0x01  // -> 4 Data Terminal Ready (MCR)
//      GND              -- 5 Signal Ground
#define DSR     0x20  // <- 6 Data Set Ready      (MSR)
#define RTS     0x02  // -> 7 Request To Send     (MCR)
#define CTS     0x10  // <- 8 Clear To Send       (MSR)
#define RI      0x40  // <- 9 Ring Indicator      (MSR)
Pokazany obok program setser pozwala ustawić stan pojedynczego bitu portu szeregowego. a getser - odczytać stan jednego bitu. Tworzymy binaria, które przydadzą się do zabawy z portem:
 gcc -O setser.c -DBIT=DTR -o setdtr
 gcc -O setser.c -DBIT=RTS -o setrts
 gcc -O getser.c -DBIT=CTS -o getcts
Do praktycznego wypróbowania programu można użyć wtyczki DB9 (żeńskiej) i diody LED połączonej szeregowo z opornikiem 910 omów. Zespół diody łączymy z końcówkami wtyczki nr 4 i 5 i umieszczamy wtyczkę w gnieździe pierwszego portu szeregowego. Teraz poleceniem setdtr 0 1 można wymusić stan wysoki na końcówce złącza, a poleceniem setdtr 0 0 - stan niski. W jednym z tych stanów dioda będzie się świecić, a w drugim zgaśnie. Przyporządkowanie świecenia/nieświecenia do stanu portu zależy od kierunku podłączenia diody. led_layout Jeszcze ładniejszy efekt uzyskamy łącząc ze sobą przeciwrównolegle dwie diody o różnych kolorach. Dodatkowo diody za darmo wzajemnie się zabezpieczają przed przepięciem w kierunku zaporowym.
Do końcówek wtyczki nr 7 i 8 przytwierdzamy mikrowyłącznik i urządzenie jest gotowe. Większość potrzebnych podzespołów można zdobyć rozpruwając starą, popsutą myszkę komputerową. Pozostałe znajdziesz w sklepie z częściami elektronicznymi. Nawet w najgorszym wypadku koszt zakupów nie powinien przekroczyć 10 zł.
Poniższy skrypt przełącza świecenie diody, oczekuje na pstryknięcie wyłącznikiem, przełącza diodę do stanu początkowego i kończy działanie. Ponieważ złącze portu nie zawiera dodatniego napięcia odniesienia, musimy je sobie wykreować, podając na czas testu "1" na wyjście RTS.
#!/bin/sh
./setdtr 0 1
./setrts 0 1
while ! ./getcts; do continue; done
./setrts 0 0
./setdtr 0 0
/* setser.c by jbw, 2004-10-17
   set/clear serial control line
   Arguments:
      serial device (0=/dev/ttyS0=COM1, 1=/dev/ttyS1=COM2...)
      0 to clear, 1 to set
*/
#include "ser.h"
#ifndef  BIT
  #define  BIT    DTR
#endif

static unsigned int ports[] = PORTS; // serial ports

int main(int argc, char **argv)
{
  int dnum = 0, value = 0, adr;
  unsigned char b;
  // get command line
  if (argc > 1)
  {
    dnum = atoi(argv[1]);
    if((dnum < 0) || (dnum > 3)) dnum = 0;
  }
  if (argc > 2) { value = atoi(argv[2]); }
  adr = ports[dnum]+MCR;
  if (ioperm(adr, 1, 1)) exit(1); // request for port access
  b = inb(adr); // get current register value
  if (value) outb(b|BIT, adr); // set BIT line
  else outb(b&~BIT, adr); // clear BIT line
  return 0; // and release port
}
/* getser.c by jbw, 2006-04-26
   Read serial port status bit
   Arguments:
      serial device (0=/dev/ttyS0=COM1, 1=/dev/ttyS1=COM2...)
*/
#include "ser.h"
#ifndef BIT
  #define BIT CTS
#endif

static unsigned int ports[] = PORTS; // serial ports

int main(int argc, char **argv)
{
  int dnum = 0, msr;
  if (argc > 1)
  { // get command line
    dnum = atoi(argv[1]);
    if((dnum < 0) || (dnum > 3)) dnum = 0;
  }
  msr = ports[dnum]+MSR;
  if (ioperm(msr, 1, 1)) return -1; // request for port access
  return (inb(msr) & BIT) == 0; // and release port
}
 
opiekun: Janusz Wiśniewski :: rejestracja odwiedzin 1643 gości
mobi