Branch crossing local variable definition

General FreeBASIC programming questions.
coderJeff
Site Admin
Posts: 2614
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Branch crossing local variable definition

Postby coderJeff » Mar 04, 2018 1:46

You may also be interested in __FILE__ and __FUNCTION__

Here's a windows example that reports module, function, line number, GetLastError(), and the system message. It also wraps the function call in a #define. Should work with UNICODE. Tested: works with fbc win32 & win64 on win7.

Code: Select all

#include once "windows.bi"
#include once "win/strsafe.bi"

#define TEXT(_s) (_s)

#define ErrorMsg( s ) ErrorMsgEx( s, __FILE__, __FUNCTION__, __LINE__ )

sub ErrorMsgEx _
   ( _
      byval lpszText as PTSTR, _
      byval lpszFile as PTSTR, _
      byval lpszFunction as PTSTR, _
      byval dwLineNumber as DWORD _
   )

   dim as LPVOID lpMsgBuf
   dim as LPVOID lpDisplayBuf
   dim as DWORD dw = GetLastError()
   const BUFSIZE = 4096

   FormatMessage( _
      FORMAT_MESSAGE_ALLOCATE_BUFFER or _
      FORMAT_MESSAGE_FROM_SYSTEM or _
      FORMAT_MESSAGE_IGNORE_INSERTS, _
      NULL, _
      dw, _
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), _
      cast(LPTSTR, @lpMsgBuf), _
      0, NULL )

   lpDisplayBuf = cast(LPVOID, _
      LocalAlloc(LMEM_ZEROINIT, _
         (lstrlen(cast(LPCTSTR, lpMsgBuf))+lstrlen(cast(LPCTSTR, lpszFunction))+BUFSIZE)*sizeof(TCHAR) _
         ) _
      )

   StringCchPrintf( cast(LPTSTR, lpDisplayBuf), _
      LocalSize(lpDisplayBuf) / sizeof(TCHAR), _
      TEXT( !"%s,\nmodule '%s',\nprocedure '%s',\nline '%d',\nstatus code '%08x',\nmessage = %s" ), _
      lpszText, lpszFile, lpszFunction, dwLineNumber, dw, lpMsgBuf)

   MessageBox(NULL, cast(LPCTSTR, lpDisplayBuf), TEXT("ErrorMsg"), MB_OK)

   LocalFree(lpMsgBuf)
   LocalFree(lpDisplayBuf)
end sub

sub MyLittleThingThatFails()

   '' simulate a windows error code
   SetLastError( ERROR_INVALID_PARAMETER )

   ErrorMsg( TEXT("What happened?") )
   
end sub

'' just say hello
ErrorMsg( TEXT("Hello World") )

MyLittleThingThatFails()
sancho3
Posts: 263
Joined: Sep 30, 2017 3:22

Re: Branch crossing local variable definition

Postby sancho3 » Mar 04, 2018 2:55

It would be interesting to see an actual procedure that requires the goto approach.
In my head I can't come up with anything that a while or do block couldn't handle.

Code: Select all

sub mysub()
dim as boolean lerror = false
while lerror = false
   do_some_things()
   if I_find_an_error() then
      exit while
   endif
   do_success_stuff()
   return
wend
do_error_stuff()
end sub

It starts to get a little complicated with nested loops but surely nothing that can't be overcome.
caseih
Posts: 1261
Joined: Feb 26, 2007 5:32

Re: Branch crossing local variable definition

Postby caseih » Mar 04, 2018 5:30

If there's a bunch of cleanup to do, you can't do that in a separate cleanup function without either global variables or a lot of parameters, sancho3.

It's extremely common in the C world to use goto to jump to a cleanup section in a function. It's fast and extremely clean. As long as you don't jump in a way that triggers the problem this thread is about, you'll have no problem with this idiom.
dodicat
Posts: 5020
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Branch crossing local variable definition

Postby dodicat » Mar 04, 2018 13:40

You can always put do as the sub start
and
exit do
loop
near the sub finish.
Then exit do anywhere (or exit while) .
But I think goto is more elegant and easier to read.

Anyway, an apparent cheat in a sub for POWERbasic fans.
Unless of course, if POWERbasic does likewise.

Code: Select all


sub dothis(f as double=rnd) static
    if f>.5 then goto finish
    dim as string s
    dim as double x
    x=f*2
    s =str(x)
    print s
    finish:
end sub

for n as long=1 to 40
 dothis
next
sleep
 
fxm
Posts: 8171
Joined: Apr 22, 2009 12:46
Location: Paris suburb, FRANCE

Re: Branch crossing local variable definition

Postby fxm » Mar 04, 2018 14:14

Without static variables, but with local variables declared without initializers:

Code: Select all

sub dothis(byval f as double=rnd)
    if f>.5 then goto finish
    dim as zstring * 23+1 s = any
    dim as double x = any
    x=f*2
    s =str(x)
    print s
    finish:
end sub

for n as long=1 to 40
    dothis
next
sleep
deltarho[1859]
Posts: 1272
Joined: Jan 02, 2017 0:34
Location: UK

Re: Branch crossing local variable definition

Postby deltarho[1859] » Mar 04, 2018 15:05

@coderJeff

I have a PB function which I have been using for many years which, in the event of an error, displays a message box with the NTE code, associated text, failing API, function and id value. It too uses FormatMessage. The code is an adaptation of code by José Roca and was extended to include NTE codes for the Windows CryptoAPI. It was on my to do list for porting to FB. It would need updating because I do write CryptoAPI anymore favouring CNG introduced in Windows Vista. However, I don't need to do that now and will use your code instead. <Ha, ha>

What surprises me is how few people check the Windows API return values. With graphics programming it can be very clear something is wrong just by looking at our screen. With numerical work we may have successful compilations and no runtime errors but they are not proof that our results are correct.

Thankyou.

Return to “General”

Who is online

Users browsing this forum: No registered users and 6 guests