I know this is against the Cnob orthodoxy, however what do you think would be the best way to mimic GOSUB in C, without using a procedure?
:-[
Interesting question, Patrice.
I find that GCC supports inner procedures, and that the outer local and static variables are visible to the inner procedure, thus perfectly mimicking a gosub.
I don't know whether VC supports this construct.
#include <stdio.h>
int main()
{
int a;
void mygosub()
{
a=4;
}
mygosub();
printf("%i",a);
}
Charles
If C can use ASM then just use the ASM INLINE Commands and a Label?
I do not know C but i would do that in PB.
It's not pretty and I'd recommend you rewriting your code but this is how bc9/bcx does it.
James
Basic code:
'==============================================================================
$CPPHDR
$ONEXIT "VC.BAT $FILE$ x86 con"
'==============================================================================
DIM j
CLS
PRINT "Calling Subroutine 9 times ..." : PRINT
FOR j = 1 TO 9
GOSUB qwerty
NEXT
PRINT : PRINT "All Done!"
END ' Don't accidently fall into the subroutine
QwErTy: ' BCX Subroutine Labels are NOT case sensitive
PRINT " This is instance >>", j, " << of the subroutine call."
RETURN ' Return from subroutine back to main program
translated to c++ and compiled with sdk 7.1 cl.
// *********************************************************************
// Created with bc9 - BASIC To C/C++ Translator (V) 9.1.2.0 (2013/02/10)
// BCX (c) 1999 - 2009 by Kevin Diggins
// *********************************************************************
// Translated for compiling with a C++ Compiler
// On MS Windows
// *********************************************************************
// Additional lines may be needed
#if defined( __cplusplus )
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
typedef std::string stdstr;
using namespace std;
#endif
#include <process.h> // dos
#include <conio.h> // dos
#include <direct.h> // dos
#include <io.h> // dos
#include <ctype.h> // dos/linux
#include <fcntl.h> // dos/linux
#include <math.h> // dos/linux
#include <stdio.h> // dos/linux
#include <string.h> // dos/linux
#include <stddef.h> // dos/linux
#include <stdlib.h> // dos/linux
#include <setjmp.h> // dos/linux
#include <time.h> // dos/linux
#include <stdarg.h> // dos/linux
#include <sys/types.h>
#include <sys/stat.h>
// ***************************************************
// types from winapi that may be needed
// ***************************************************
typedef char *PCHAR,*LPCH,*PCH,*NPSTR,*LPSTR,*PSTR;
typedef unsigned int UINT;
typedef unsigned long DWORD,ULONG;
typedef unsigned char UCHAR,byte;
typedef void *PVOID,*LPVOID;
//----------------------------------------------------
// this is missing From MinGWTDM64 stdlib.h
//----------------------------------------------------
#if defined(__MINGW32__) || defined(__MINGW64__)
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
#endif
//----------------------------------------------------
// *************************************************
// User's GLOBAL ENUM blocks
// *************************************************
// *************************************************
// System Defined Constants
// *************************************************
#define CCPTR const char*
#define cSizeOfDefaultString 2048
// *************************************************
// User Defined Constants
// *************************************************
// *************************************************
// Standard Prototypes
// *************************************************
void cls(void);
// *************************************************
// User Defined Types And Unions
// *************************************************
// *************************************************
// System Variables
// *************************************************
jmp_buf GosubStack[32];
int GosubNdx;
// *************************************************
// User Global Variables
// *************************************************
static PCHAR *g_argv;
static int g_argc;
static int j;
// *************************************************
// User Global Initialized Arrays
// *************************************************
// *************************************************
// Runtime Functions
// *************************************************
void cls (void)
{
system("cls");
}
// ************************************
// User Subs and Functions
// ************************************
// *************************************************
// Main Program
// *************************************************
int main(int argc, char *argv[])
{
g_argc = argc;
g_argv = argv;
cls();
printf("%s\n","Calling Subroutine 9 times ...");
printf("\n");
for(j=1; j<=9; j+=1)
{
if (setjmp(GosubStack[GosubNdx++])==0) goto QWERTY;
}
printf("\n");
printf("%s\n","All Done!");
fflush(stdout);
exit(0);
QWERTY:;
printf("%s% d%s\n"," This is instance >>",(int)j," << of the subroutine call.");
longjmp (GosubStack [--GosubNdx],1 );
return 0; /* End of main program */
}
James, Theo, Charles,
Microsoft discourage the use of setjmp/longjmp (http://msdn.microsoft.com/en-us/library/yz2ez4as(v=vs.80).aspx) within C++ program.
But i am unsure if this would impact the code, because the (gosub) jmp is done inside of the same procedure.
...
Patrice,
On further research, I find that VC++, Clang and Objective C compilers do not support nested procedures unfortunately, only GCC (MinGw). I was rather shocked at the amount of baggage that accompanies a VC installation! GCC does it plain and simple.
Charles
PowerBasic does it clean and simple.
Quote from: Patrice Terrier on February 13, 2013, 09:42:57 AM
James, Theo, Charles,
Microsoft discourage the use of setjmp/longjmp (http://msdn.microsoft.com/en-us/library/yz2ez4as(v=vs.80).aspx) within C++ program.
But i am unsure if this would impact the code, because the (gosub) jmp is done inside of the same procedure.
...
Patrice,
My "c" is not the best but my interpretation of the link is the same as yours. Go for it as it appears you maybe walking a tightrope anyway using VC++ to write what is in actuality "c" code not c++.
James
Quote
I was rather shocked at the amount of baggage that accompanies a VC installation! GCC does it plain and simple.
Couple years back I bought VStudio 2008 Pro. I told the setup utility to install everything for me. It added 20 gigabytes to my harddrive! 20 gigs! Couldn't believe it.
As far as the setjmp/lngjmp thing, I've never used those, so have no idea.
Fred,
I am looking for a good UNICODE string class, are you aware of any?
...
Well, the one you've been using from the C++ Standard Library has a wide character string counterpart. I'll check its usage here in a second after I post this. I'm a little hazy on the name because I use my own string class and have only used the C++ Std. one a couple times. Just a second ...
Yea, here we go ...
#ifndef UNICODE //This program creates a window upon which are displayed
#define UNICODE //continuously updated mouse coordinates, left button
#endif //click positions, window sizing information, and key
#ifndef _UNICODE //presses (concatenated together for simple text display).
#define _UNICODE
#endif
#include <windows.h>
#include <tchar.h>
#ifdef UNICODE
#define String std::wstring
#else
#define String std::string
#endif
I thought it was just std::wstring, but didn't want to post until I was sure. As you can see in the above excerpt from a program of mine, you can fool around with it with macros so as to use either ansi or wide strings.
The string handling I do in C++ is fairly simple so I use my own class which can be run ansi or unicode. It compiles smaller than the Std Lib one. Actually, its posted here on your forum ...
http://www.jose.it-berater.org/smfforum/index.php?topic=4615.45
in reply 49.
The actual string class is on my board in the COM section, and there is a link there in reply 49.
The Std. Lib one is likely the way to go, unless shaving 10 or 20K from a dll/exe is critical to you. I almost hate to say why I created my own. Basically, from my own dumbness and failure to do the research, I didn't know the C++ Std. Lib. had one. That was about 10 years ago, so I started creating my own. It was a good learning experience and fun.
It was just a couple weeks ago when I posted that example in your forum Patrice, and that was during a time I was playing with that 64 bit GNU compiler James Fuller turned me on to. I was happy and amazed when it compiled my string class as 64 bit without any warnings or errors. Sometimes I just get lucky I guess!
I know you like the Microsoft C/C++ compiler with VS, but I'd have to say the Mingw C\C++ compiler suite is worth looking into.
GNU compilers seem to cover all platforms - including Android :)
Here's an interesting little tidbit of info James might be interested in ...
... to time the compilation speed of the mingw compiler, use this switch in your compiler string ...
-ftime-report
It produces a report.
I've found the older compiler with my Code::Blocks installation is much faster than the newer one I downloaded a month ago. Also, the PowerBASIC compiler has really slowed down. I guess the dead code removal.
I know you like the Microsoft C/C++ compiler with VS
The reason why i use Visual Studio, is that it embraces all the Microsoft technologies within a single package, including managed and un-managed code.
So far, if C# would have been able to produce un-managed code, that would have been my compiler of choice. But i don't like the use of the extra frame-work, and the garbage collector manager. Non-obstant the fact, that i am writing mostly "unsafe" code ;)
Thus i put my choice on C/C++ without ATL and MFC, because i want to produce code without extra runtime, and i want to have direct control on what is going on under the hood, but i really hate the C/C++ syntax and the strong type they are using, HWND, HBITMAP, HANDLE, etc., when all could be replaced by DWORD. Also i never know exactly where to put the "*" when declaring/working with pointers.
Translating my GDImage to produce a 64-bit version is a very slow process, because i have to learn all the C/C++ oddities at the same time :(
...
Patrice,
Are you now prepared to submit to the anti-gosub mind clamp? :)
The only other sensible way is to OOPify your code so that all member variables can be shared between member functions (methods).
Quote
The only other sensible way is to OOPify your code so that all member variables can be shared between member functions (methods).
That's the beauty of inlining class members; it saves the overhead of a seperate function call, which, of course, is what gosub does.
I'll tell you what Patrice, I've had trouble over the years between the slightly different pointer notation between PowerBASIC and C. They are so similiar, but yet there are subtle differences that drives one crazy. I do have various code snippets handy outlining the differences perhaps you would be interested in. Because I use pointers so heavily in my work, I've spent countless hours playing around with these things.
QuoteAre you now prepared to submit to the anti-gosub mind clamp?
No, i will go the evil's way using couples of jmp/GOTO, because i am lazy and i want to keep the C code, close to the PB's original.
Did i say i like spaghetti ;D
...
Here is an example of C code that drives me nut.
Code in red causes:
Error: a pointer bound to a function may only be used to call a functiontypical syntax problem i am faced with...
Quote#include <windows.h>
#include "stdafx.h"
#include <vector>
#include <string.h>
using namespace std;
wstring zGetCTLText(IN HWND hCtrl) {
std::wstring sBuf;
long bufsize = 4096;
vector<WCHAR>buf(bufsize);
long length = min(GetWindowText(hCtrl, &buf[0], bufsize), bufsize);
return wstring(buf.begin(), buf.begin() + length);
}
int _tmain(int argc, _TCHAR* argv[])
{
HWND hWnd = GetForegroundWindow();
wstring sCaption = zGetCTLText(hWnd);
if (sCaption.length) { printf("%s", sCaption); }
return 0;
}
And you know what, the problem is because the ".length" member must be followed by two empty (), like this:
if (sCaption.length
()) { printf("%s", sCaption); }
>:(
Patrice, I've encounter the same problem while learning C#....forgetting to include the trailing open and close parenthesis when calling a method. Once I made the mistake and figured out the solution then I've been okay ever since. Coming from a VisualBasic background, we never had to include the parenthesis. I guess that "C" languages are more strict.
Paul
The C# syntax is much more easier to read/write from my opinion, but it is managed code ???
...
That doesn't bother me about needing the brackets () on member function calls. I'm more bothered with languages that don't require it (such as vb I believe - PB too?), as it seems to overlook the distinction between ordinary variables and member functions.
Patrice, what does this do
vector<WCHAR>buf(bufsize);
Create a vector whose upper limit of growth is restricted to bufsize, as opposed to the standard behaviour of unlimited growth?
Anyway, how is your function to get text from a control any better than this (short compilable example)...
//Main.cpp - Developed with Code::Blocks / mingw; compiles to 57 k for me with 10.05 / 95 k with 12.11.
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
#include <string>
#define IDC_BUTTON 1600
std::wstring strGetText(HWND hCtrl)
{
TCHAR szBuffer[4096];
GetWindowText(hCtrl,szBuffer,4096);
return std::wstring(szBuffer);
}
LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
HINSTANCE hIns=((LPCREATESTRUCT)lParam)->hInstance;
CreateWindowEx(0,_T("button"),_T("Click Me!"),WS_CHILD|WS_VISIBLE,75,50,150,30,hwnd,(HMENU)IDC_BUTTON,hIns,0);
return 0;
}
case WM_COMMAND:
{
if(LOWORD(wParam)==IDC_BUTTON)
{
HWND hMain=GetForegroundWindow();
MessageBox(hwnd,strGetText(hMain).c_str(),_T("Your Text..."),MB_OK);
}
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
TCHAR szClassName[]=_T("Text Wrapper Demo");
WNDCLASSEX wc={};
MSG messages;
HWND hWnd;
wc.lpszClassName = szClassName;
wc.lpfnWndProc = fnWndProc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
wc.hInstance = hInstance;
RegisterClassEx(&wc);
hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,200,175,320,200,HWND_DESKTOP,0,hInstance,0);
ShowWindow(hWnd,iShow);
while(GetMessage(&messages,NULL,0,0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
Quotehow is your function to get text from a control any better than this
that was learning code to check the use of VECTOR (to mimic dynamic array), not production code.
...
Quote
that was learning code to check the use of VECTOR (to mimic dynamic array), not production code.
Oh! :)
I'm such a minimalist by nature, once I understand something that looks overly complicated, I always start to thinking, "Boy! I bet we could get rid of this or that or whatever!"