12. december 2000 - 18:45Der er
34 kommentarer og 1 løsning
Løkke
Jeg et styk kode (jeg fandt) som jeg gerne vil lave om på. Jeg er ikke så glad for goto sætninger og vil derfor gerne lave det om til en while eller repeat sætning. Jeg har forsøgt på mange mådet men jeg kan ikke komme ud af løkken. Er der pga socket\'ens errorcode at jeg ikke kan sæt det hele ind i en while løkke?
procedure TForm1.psError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); label son; begin errorcode:=0; edit4.text:=\'Scanned Port No : \'+inttostr(portno); ps.active:=false; portno:=portno+1; if portno > strtoint(edit3.text) then goto son else ps.address:=edit1.text; ps.port:=portno; ps.active:=true; son:
De fleste virksomheder har efterhånden bevist, at AI virker.
Pilotprojekter leverer resultater. Medarbejdere bruger generative AI-værktøjer. Nye use cases dukker op på tværs af organisationen.
Jeg et styk kode (jeg fandt) som jeg gerne vil lave om på. Jeg er ikke så glad for goto sætninger og vil derfor gerne lave det om til en while eller repeat sætning. Jeg har forsøgt på mange mådet men jeg kan ikke komme ud af løkken. Er der pga socket\'ens errorcode at jeg ikke kan sæt det hele ind i en while løkke?
procedure TForm1.psError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); label son; begin errorcode:=0; edit4.text:=\'Scanned Port No : \'+inttostr(portno); ps.active:=false; portno:=portno+1; if portno > strtoint(edit3.text) then break else ps.address:=edit1.text; ps.port:=portno; ps.active:=true;
Break bryder en while, for, repeat, men hopper ikke ud af en procedure. Det gør exit derimod. Iøvrigt er der ikke rigtig noget problem med en kontrolleret brug af goto. Den oprindelige kode er bestemt overskuelig. Men den kan altså også skrives:
procedure TForm1.psError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin errorcode:=0; edit4.text:=\'Scanned Port No : \'+inttostr(portno); ps.active:=false; portno:=portno+1; if portno > strtoint(edit3.text) then exit; ps.address:=edit1.text; ps.port:=portno; ps.active:=true; end;
Så må jeg have mange gotos til gode! Har ikke brugt dem siden de gode gamle dage i Basic på en ZX81 med hele 1KB RAM
Kan det for øvrigt ikke løses med et enkelt NOT? Sådan. Eller overser jeg noget?
procedure TForm1.psError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin errorcode:=0; edit4.text:=\'Scanned Port No : \'+inttostr(portno); ps.active:=false; portno:=portno+1; if NOT(portno > strtoint(edit3.text)) then begin ps.address:=edit1.text; ps.port:=portno; ps.active:=true; end; end;
Ja, er det ikke skønt. Man kan altid undgå disse forbudte GOTO, BREAK og EXIT. Hvis ikke bør man kikke koden igen. Netop som surreal har gjort i dette tilfælde.
Ja ja ... Break kan undgåes men den er da snedig ... her er to eksempler hvor jeg villler bruge break :
procedure TForm1.Button1Click(Sender: TObject); begin if not OpenDialog1.Execute then exit; Caption := OpenDialog1.FileName; end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if not (ssShift in Shift) then exit; Caption := \'Shift pressed\'; end;
det sparet et sæt begin end og gør koden nemmere at læse ....
Goto kan bruges når du skriver optimeret kode fordi den danner et jump når det bliver kompileret ...
Jeg er hu ikke særlig enig med dig. I de 2 eksempler du viser er det så smipelt at undgå EXIT ved at benytter IF-THEN-ELSE at jeg ikke forstår pointen i at lade være.
Nå, kode-stil er jo forskellig. Jeg er måske også lidt af den gamle skole (den gang det hele skulle være så \"over-struktureret\") :o)
Jeg er jo ikke en af disse hersens C-programmøre ;o)
Lidt omskrivning af dine eksempler. NOT fjernes så du undgår EXIT. Jeg bryder mig nemlig heller ikke meget om nægtene udsagn :o)
procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then Caption := OpenDialog1.FileName; end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (ssShift in Shift) then Caption := \'Shift pressed\'; end;
Som sagt er det nok et spørgsmål om kodestil. Jeg foretrækker det sådan, men har ingen problemer med at læse din kode. Der hvor jeg ikke kan lide EXIT er hvor folk benytter det 5-10 gange i en procedure som erstatning for at strukturere koden rigtigt (LÆS: Tænke lidt over hvad der skal udføres).
Jeg er helt med på at i mine små eksempler er det tæt på misbrug at bruge exit, men var der nu 200 linjers kode i proceduren så var sagen en anden ....
generelt bruger jeg kun exit til at styre hoved flowet med. Altså i det tilfælde hvor jeg vil gøre ingen ting hvis en kondition ikke er opfyldt ... Der synes jeg det er smart .... men en 5-6 stylkker fordi man ikke har 200% styr på sit flow det bryder jeg mig heller ikke om.
Hmmn ... C++ er der nu ikke noget i vejen med .. Jeg kunne nemt komme i tanke om en 5-6 ting jeg mangler i Delphi som c++ har ...
Udover de skulle de (borland) lige tage og rette den pinlige fejl der er i deres procedure over loading.
Se blot på det følgende. Det er ikke tilladt i Delphi :
function Hest(a : Integer) : Integer;overload; begin result := a; end;
function Hest(a : Integer) : Real;overload; begin result := a; end;
procedure Hest(a : Integer);overload; begin result := a; end;
Ja, jeg syntes nok der var lidt C-programmør over dig *LOL*
Mon det du kalder en \"fejl\" ikke stammer fra den meget stramme type-kontrol der var i de første vorsioner af Pascal (Compas-pascal, Poly-pascal mv.). Det var netop det der var kendetegnende ved Pascal. Siden er der blevet mulighed for at lave nogle af de \"langhårede\" ting som f.eks. nogle finder stærkt i C++.
PS: Lad os ikke starte en diskussion om Pascal kontra C++. Det var ikke det spørgeren ville med sit spørgsmål.
Borrisholt> \"Der var den\" - jeg troede at vi gik julen i møde - helt uden \"Hest\" ;-)
Ovenstående \"C eksempel\" har jeg ikke før set/hørt om, og min første indskydelse var da også at det ikke kunne lade sig gøre. Men det skulle i teorien nok kunne være muligt da compileren kan se typen af den variable der skal have værdien, hvorved at den også kan se hvilken funktion der skal kaldes (f.eks. \"IntegerVar := Hest(IntegerVar)\" eller \"RealVar := Hest(IntegerVar)\" !?.
Nu hvor vi er ved brugen af diverse \"breaks\" så vil jeg da lige give mit \"B7\" med:
- \"Labels\" og \"Goto\" burde ikke være tilladt, men som Borrisholt siger så kan det være med til at optimere noget kode så hvis man vil bruge det så \"har man selv være ude om det\" (i min bog så \"gør man i nælderne\").
- \"Breaks\" har helt bestemt sin berettigelse. Lad og forestille os at vi har en løkke hvor vi leder efter en eller flere betingelser som kan afbryde løkken. Dette kan godt laves med både repeat..until og while..do hvor selve løkken fortælller hvornår denne skal afbrydes. Men hvad nu hvis der er mange forskellige betingelser der kan betyde at løkken skal afbrydes, så bliver vores løkke meget uoverskuelig \"while ((a = c) or (d = a)) and ... 5 linier sener ... not(a = c)\". Ved brug af \"Break\" så kan hver af disse betingelser skrives for sig selv og bliver derved nemme at over.
- \"Exit\" har på samme måde som ovenstående sig berettigelse. At programmet bliver sværere at læse hvis der er brugt EXIT eller ej er en smagssag. Hvis man ikke bruger EXIT så er man nødt til at kigge proceduren/functionen igennem for at se om der kommer mere (ingen problem hvis denne fylder 3 linier, men hvis den fylder 5 skærme så er det en anden sag). Hvis man derimod bruger en EXIT så er ingen i tvivl om \"hvor skabet skal stå\". Jeg vil ikke sige at jeg bruger den ofte, men hvis der er tale om \"store funktioner/procedure\" (hvor der er \"risiko\" for mange \"levels\" af begin..end) så er der nok større chance for at jeg finder på at bruge den.
- En ting I ikke har nævnt ovenstående er \"Exceptions\". Disse falder heller ikke altid i god jord hos Pascal-programmøre (da de til en hvis grænse er at sammenligne med \"Break\" og/eller \"Exit\"), men har man først lært at bruge dem så er de nu gode at have.
- En sidste ting jeg vil nævne er brugen af de boolske operatore disse kan også være medvirkende til at gøre et program mere eller mindre læstbart. F.eks. så er det nemmere at læse \"a=b\" i stedet for \"not(a<>b)\" (navnlig hvis \"a\" og \"b\" i stedet var 2 funktioner hver med +5 parametre).
pellelil >> Ingen ædruelig programmør laver da en procedure, der fylder \"...den fylder 5 skærme..\" =:o)
Hvis han gør er det ikke en undskyldning for at bruge fy-ord som BREAK og EXIT. Måske han skulle prøve at nedbryde sin kode i flere selvstændige procedure og funktioner ;o)
microtec> Som vi siger på Jydsk \"så skal du ikke komme og lærer en gammel røv at sk...\" :-)
Hvilken funktion taler vi om? Er det en simple funktion til at ombryde en streng eller en simpel procedure der skal reagere på en tryk knap så fylder det ikke 5 skærme. Men når man laver \"rigtige programmer\", så er man nogle gange nødt til det.
Jeg har \"i mit tidligere liv\" bland andet være medvirkende i et softwarehus hvor vi udviklede systemer til styring af produktions-processer. I dette sammenhæng havde vi nogle \"store\" funktioner og nogle ting var måske ikke så pænt lavet i sourcen men i det sammenhæng var millisekunder lig med evigheder så der skulle spares hvor der spares kunne.
En sådan funktion/procedure kan måske i nogle sammenhæng \"gøres mindre\" hvis man enten bruger nestede funktioner eller hvis man flytter noget af den ud i en anden/mindre funktion. Men hvis denne del \"er så speciel\" at den alligevel ikke kan bruges andre steder i sourcen så ser jeg ingen grund til at a flytte den ud: du får på den måde blot et overhead i form af jumps og push/pop på stakken (når parametre skal overføres).
BREAK og EXIT er ikke fy-ord, men brugen af dem kan lige som alt andet overdrivers. Hvis du eksempelvis kigger på et C-program\'s Return (vores Result) så vil en C funktion automatisk afbryder når funcktionen værdi sættes. Jer ser ikke et problem hvis man i Pascal vælger at gøre det på samme måde ved at sætte en EXIT efter Result := xxx.
Nu kommenterede du slet ikke \"Exceptions\" men hvis du ikke \"har det så godt\" med BREAK/EXIT så har du det vel på samme måde med Exceptions !?
Nu \"hvor vi er i gang\" har jeg lige fundet et eksempel. Jeg sad i sidste uge og hjalp en ven med at \"oversætte\" noget C-programmering til Delphi (se nedenstående). Hvor der netop er en del EXIT\'er. Den primære grund til at de EXIT\'er er der, er at C-programmet bruger \"Return FALSE;\" som i Pacal vil svare til \"Result := False; Exit;\". Skulle jeg have lavet det uden brug af EXIT ville jeg blot ende om med \"for mange\" begin..end\'er inde i hinanden. Ergo min påstand er at EXIT i dette sammenhæng er nemmere at læse end de mange begin..end\'er - men vi lever da heldigvis i et frit land, hvor vi hver især kan gøre som vi har det bedst med :-)
<SNIP> Function FSUIPC_Open(dwFSReq : DWORD; var dwResult : DWORD) : Boolean; var szName : AnsiString; fWideFS : Boolean; nTry : Integer; i : Integer; begin nTry := 0; fWideFS := False; i := 0;
// abort if already started if (m_pView <> Nil) then begin dwResult := FSUIPC_ERR_OPEN; Result := False; Exit; end; // Clear version information, so know when connected FSUIPC_Version := 0; FSUIPC_FS_Version := 0;
// Connect via FSUIPC, wich is known to be FSUIPC\'s own // and isn\'t subject to user modification m_hWnd := FindWindowEx(0, 0, PChar(\'UIPCMAIN\'), Nil); if (m_hWnd = 0) then begin // If there\'s no UIPCMAIN, we may be using WideClient // which only simulates FS98 m_hWnd := FindWindowEx(0, 0, PChar(\'FS98MAIN\'), Nil); fWideFS := TRUE; if (m_hWnd = 0) then begin dwResult := FSUIPC_ERR_NOFS; Result := FALSE; Exit; end; end; // register the window message m_msg := RegisterWindowMessage(FS6IPC_MSGNAME1); if (m_msg = 0) then begin dwResult := FSUIPC_ERR_REGMSG; Result := FALSE; Exit; end;
// create the name of our file-mapping object Inc(nTry); // Ensures a unique string is used in case user closes and reopens szName := Format(\'%s:%X:%X\', [FS6IPC_MSGNAME1, GetCurrentProcessId, nTry]);
// stuff the name into a global atom m_atom := GlobalAddAtom(PChar(szName)); if (m_atom = 0) then begin dwResult := FSUIPC_ERR_ATOM; FSUIPC_Close; Result := FALSE; Exit; end;
// create the file-mapping object m_hMap := CreateFileMapping(THANDLE($FFFFFFFF), // use system paging file Nil, // security PAGE_READWRITE, // protection 0, MAX_SIZE+256, // size PChar(szName)); // name
if ((m_hMap = 0) or (GetLastError = ERROR_ALREADY_EXISTS)) then begin dwResult := FSUIPC_ERR_MAP; FSUIPC_Close; Result := FALSE; Exit; end;
// get a view of the file-mapping object m_pView := MapViewOfFile(m_hMap, FILE_MAP_WRITE, 0, 0, 0); if (m_pView = Nil) then begin dwResult := FSUIPC_ERR_VIEW; FSUIPC_Close; Result := FALSE; Exit; end;
// Okay, now determine FSUIPC version AND FS type m_pNext := m_pView;
// Try up to 5 times with a 100msec rest between each // Note that WideClient returns zeros initially, whilst waiting // for the Server to get the data while ((i < 5) and ((FSUIPC_Version = 0) or (FSUIPC_FS_Version = 0))) do begin Inc(i); // Read FSUIPC version if (not FSUIPC_Read($3304, 4, @FSUIPC_Version, dwResult)) then begin FSUIPC_Close; Result := FALSE; Exit; end;
// and FS version and validity check pattern if (not FSUIPC_Read($3308, 4, @FSUIPC_FS_Version, dwResult)) then begin FSUIPC_Close; Result := FALSE; Exit; end;
// write our Library version number to a special read-only offset // This is to assist diagnosis from FSUIPC logging // But only do this on first try if (i<2) and (not FSUIPC_Read($330A, 4, @FSUIPC_Lib_Version, dwResult)) then begin FSUIPC_Close; Result := FALSE; Exit; end;
// Actually send the request ang get the responses (\"process\") if not(FSUIPC_Process(dwResult)) then begin FSUIPC_Close; Result := FALSE; Exit; end;
// Maybe running on WideClient, and need another try Sleep(100); // Give it a chance end;
// Only allow running on FSUIPC 1.998e or later // with correct check pattern $FADE if ((FSUIPC_Version < $19980005) or ((FSUIPC_FS_Version and $FFFF0000) <> $FADE0000)) then begin if fWideFS then dwResult := FSUIPC_ERR_RUNNING else dwResult := FSUIPC_ERR_VERSION; FSUIPC_Close(); Result := FALSE; Exit; end;
FSUIPC_FS_Version := (FSUIPC_FS_Version and $ffff); // Isolates the FS version number // Optional user specific FS request if (dwFSReq <> 0) and (dwFSReq <> FSUIPC_FS_Version) then begin dwResult := FSUIPC_ERR_WRONGFS; FSUIPC_Close; Result := FALSE; Exit; end;
dwResult := FSUIPC_ERR_OK; Result := TRUE; end; </SNIP>
Jeg laver faktisk selv software til b.la. produktions-udstyr og andet hardware-nær SW (embedded- og PC-software), så jeg kan godt følge dig. Man må gå på kompromis nogen gange.
Det med millisekunder og \"evigheder\" kan da vist ikke være når du programmere i Delphi, eller et andet Windows udviklingssystem. Ellers må den \"gamle røv\" gerne lære mig noget (Er også selv jyde). 1mS er MEGET hurtigt under Windows (noget helt andet når vi snakker om embeddede systemer).
JA, da Delphi kom frem havde jeg det heller ikke særligt godt med Exceptions *LOL*. Det kan godt være jeg har været med på banen for længe (Compas pascal, Poly Pascal, Turbo Pascal), men jeg mener stadig Exceptions, og \"fy-ordene\" bryder med hele ideen i Pascal).
pellelil >> som sagt i mine tidligere kommentare så er kodestil helt sikkert forskellig.
*Drille-drille* Det skal vel også gå galt når man oversætter noget så ustruktureret som C-kode til Pascal ;o) (Kun for drille dig. Behøver ikke at kommenteres).
Ok, ok - jeg indrømmer at jeg måske overdrev lidt med millisekunderne (og \"den gang\" var det forøvrigt DOS). Men har du et transportbånd der flytter sten (i store mænger) op i en cement-blander så kan et \"langsomt system\" godt betyde at du \"ødelægger\" blandingen, og sker dette når man er ved at lave en glideforskalning til en storbælts-bro så kan jeg da kun forstille mig at forsvarret ville nyde at bortsprænge et segment der ikke lever op til kravene :-)
Pellelil > Jeg arbejder med det system, som du omtaler. Jeg vil give dig ret, med nødvendigheden af store procedurer og kæmpe if sætninger. Der er i hvert fald nogen før min tid som kunne lave meget store if sætninger og while/repeat løkker !!!!!
Det er da ikke noget at \"bære\" over med. Kommentaren var bare til ham der oprettede spørgsmålet. Jeg mener der svarret og så er der ikke noget formål med at holde det åben.
Må vi andre ikke godt høre hvad du gjorde? Det er så kedeligt at slutte et spørgsmål med \"Jeg fandt selv ud af det\". Så er der ikke andre der kan få gavn af det :o)
Det lader ikke til at surreal kommer med svaret om hvad han fandt ud af, så derfor vil jeg her give min løsning på hvordan koden kan skrives unden, goto etc :
procedure TForm1.psError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin ErrorCode:=0; Edit4.Text:=\'Scanned Port No : \'+IntToStr(PortNo); Ps.Active:=false; inc(PortNo);
if PortNo < StrToInt(Edit3.Text) then begin Ps.Address:=edit1.text; Ps.Port:=portno; Ps.Active:=true; end; end;
Mon ikke surreal mente en anden løsning når han skriver \"Jeg fandt selv ud af det\" :o)
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.