Powerbasic Museum 2020-B

IT-Consultant: Patrice Terrier => C++ programming (SDK style) => Topic started by: Patrice Terrier on May 11, 2013, 03:01:07 PM

Title: PB to C/C++ pitfalls
Post by: Patrice Terrier on May 11, 2013, 03:01:07 PM
For PB's programmer wanting to make the big jump, there are several pitfalls you must be aware when porting from PB to C/C++.
Title: Re: PB to C/C++ pitfalls
Post by: James C. Fuller on May 11, 2013, 04:37:40 PM
Patrice,
  My c++ is horrid but can't you assign a {0} instead of using memset?

James
Title: Re: PB to C/C++ pitfalls
Post by: James C. Fuller on May 11, 2013, 05:04:32 PM
I just found this on a forum:

Some quick testing indicates that Microsoft's x86 compiler generates different assembly if the initializer list is empty, compared to when it contains a zero. Maybe their ARM compiler does too. What happens if you do this?

byte a[10] = { };
Here's the assembly listing I got (with options /EHsc /FAs /O2 on Visual Studio 2008). Note that including a zero in the initializer list causes the compiler to use unaligned memory accesses to initialize the array, while the empty initializer list version and the memset() version both use aligned memory accesses:

; unsigned char a[10] = { };

xor   eax, eax
mov   DWORD PTR _a$[esp+40], eax
mov   DWORD PTR _a$[esp+44], eax
mov   WORD PTR _a$[esp+48], ax

; unsigned char b[10] = { 0 };

mov   BYTE PTR _b$[esp+40], al
mov   DWORD PTR _b$[esp+41], eax
mov   DWORD PTR _b$[esp+45], eax
mov   BYTE PTR _b$[esp+49], al

; unsigned char c[10];
; memset(c, 0, sizeof(c));

mov   DWORD PTR _c$[esp+40], eax
mov   DWORD PTR _c$[esp+44], eax
mov   WORD PTR _c$[esp+48], ax
Title: Re: PB to C/C++ pitfalls
Post by: Patrice Terrier on May 11, 2013, 05:09:36 PM
Yes, you can assign {0}

however when building dynamic array of structure, i would recommend to use memset.

Example of allocating a dynamic array:
ZSLIDESHOW* PlayList = new ZSLIDESHOW[resizeValue];
memset(PlayList, 0, sizeof(ZSLIDESHOW) * UB); // Fill up the whole new array with nulls (to mimic what PB's does)
//
...
//
delete []  PlayList
<-- Never forget to release the memory allocated on the fly!
Title: Re: PB to C/C++ pitfalls
Post by: Patrice Terrier on May 11, 2013, 05:23:22 PM
The Pitfall list has been updated with select/switch.
Title: Re: PB to C/C++ pitfalls
Post by: Patrice Terrier on May 13, 2013, 08:42:05 AM
The pitfall list has been enhanced with:
QuoteDouble check the IF syntax when doing comparisons
Title: Re: PB to C/C++ pitfalls
Post by: Kev Peel on May 15, 2013, 08:55:41 PM
Hello Patrice,

I am also using Visual C++ entirely for my projects now (well since beginning of 2012). With PB, I found myself hitting brick walls whilst debugging large projects and the Visual Studio debugger is so much more powerful.

Use the following statement to stop compilation when it finds common mistakes in your code:

// [C4101=unused locals, C4013=missing proc, C4700=uninit vars, C4701=potentially uninit vars, C4702=unreachable code, C4706=if assignment, C4715=control paths, C4716=no return value, 4047=indirection]
#pragma warning( error : 4700 4701 4702 4706 4047)

C4700, C4702 and C4716 are most useful!

I devised a common #include .H file with this and other basic stuff, such as typedefs and functions such as reset().
Title: Re: PB to C/C++ pitfalls
Post by: Kev Peel on May 15, 2013, 09:06:12 PM
Also as char (PB: BYTE) is signed by default, this can create problems with legacy PB code.

Use the following:

#ifndef RC_INVOKED
#ifndef _CHAR_UNSIGNED
  #error "COMPILATION ERROR: CHAR TYPE MUST BE UNSIGNED"
#endif
#endif


You need /J in CL compiler options to fix that one
Title: Re: PB to C/C++ pitfalls
Post by: Patrice Terrier on September 19, 2013, 11:50:06 AM
The pitfall list has been enhanced with string comparisons.

Performing string comparisons
PowerBASIC uses the equal sign or angle brackets for string comparison example:
IF String1$ = String2$ THEN
IF String1$ <> String2$ THEN
but In C/C++ you can't do this and expect the same result, because "==" or "!=" C/C++ would perform a pointer comparison instead of string comparison.
In order to get the good result you have to use _wcsicmp or strcmp, this way:
if ((_wcsimp(zClass, L"BUTTON") == 0) { // Check if the two strings are the same
The function returns an integer value indicating the relationship between the strings:
A zero value indicates that both strings are equal.
A value greater than zero indicates that the first character that does not match has a greater value in str1 than in str2;
And a value less than zero indicates the opposite.
Title: Re: PB to C/C++ pitfalls
Post by: James C. Fuller on September 19, 2013, 02:56:21 PM
Patrice,
  It appears you are showing a direct translation from PB to c++ ?

I prefer to use c++ compare.

James


#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif

#include <iostream>
#include <string>
using namespace std;

int main ()
{
string  s1;
string  s2;
wstring  ws1;
wstring  ws2;
  s1="James";
  s2="Fuller";
  ws1= L"James";
  ws2= L"Fuller";
  if(s1.compare("James")==0 )
    {
      cout<<"YES"<<endl;
    }
  else
    {
      cout<<"NO"<<endl;
    }
  if(ws1.compare(L"James")==0 )
    {
      cout<<"YES"<<endl;
    }
  else
    {
      cout<<"NO"<<endl;
    }
  system("pause");
  return 0;
}


Title: Re: PB to C/C++ pitfalls
Post by: Patrice Terrier on September 19, 2013, 04:34:25 PM
James--

QuoteIt appears you are showing a direct translation from PB to c++ ?

No, i am showing the use of _wcsicmp or strcmp, when using CHAR or WCHAR comparison :)

but compare is fine when using string or wstring.
Title: Re: PB to C/C++ pitfalls
Post by: James C. Fuller on October 31, 2013, 09:00:23 PM
Patrice,
  Another item is scope of variables. j is only visible within the if scope here.

  int i = 1;

  if(i) == 1 {
    int j = 7;
  } 

//  this will get you an error
  std::cout << j << endl
Title: Re: PB to C/C++ pitfalls
Post by: Mike Stefanik on October 31, 2013, 11:30:05 PM
Even more fun is that you can do something like this:


void foobar()
{
    int i, x;
   
    // a lot of code goes here
   
    for (i = x = 0; i < 10; i++)
    {
        // even more code goes here
   
        if (i % 5)
        {
            int x, y, z;
   
            // put even more code here
   
            x += i; // doing something with x
           
            // and some more code here
        }
    }

    // and if the function isn't huge enough, add some more code
    // to make sure the kitchen sink is included
}


Now, a good compiler that's set to issue fairly strict warnings should complain about the fact that you're using an uninitialized 'x' ... and you may scratch your head for a second thinking, "hey, I've initialized 'x' at the top of the for loop there!" Then the proverbial light bulb will come on over your head.