Announcement

Collapse
No announcement yet.

Specific C-porting questions

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Specific C-porting questions

    I need some help porting a few C items to PB and it's been many
    years since I did any significant C programming, so I hope these
    questions aren't too dumb (a teacher once told me, "There are no
    dumb questions, only dumb students!").

    These items are all from a C header file (.h):
    Code:
    typedef struct ABC123__ { int unused; } FAR* ABC123;
    The ABC123 is then used in a function prototype like this:
    Code:
    extern __declspec( dllimport ) HWND SomeFunction(ABC123);
    My translation is:
    Code:
    Declare Sub SomeFunction Lib "SomeLibrary.DLL" Alias "SomeFunction" (dwValue as DWORD)
    Next problem is what appears to be a linked list; here's the C form:
    Code:
    typedef struct tag_AnItem {
       UINT        param1;
       UINT        param2;
       UINT        param3;
       struct tag_AnItem *next;
    } AnItem;
    My PB translation:
    Code:
    Type AnItem
       param1		As WORD     ' Or use DWORD?
       param2		As WORD 						
       param3		As WORD 						
       next_oc		As DWORD    ' Pointer to a structure is a DWORD?		
    End Type
    When converting C pointer declares, is a DWORD ok for any variable type
    or should one use the explicit pointer type, such as 'DOUBLE PTR'? For example:
    Code:
    typedef struct {					
        int        param1;
        double     *a;
        double     *b;
    } SomeData;
    PB:
    Code:
    Type SomeData										
        param1 	As LONG
        a		As DOUBLE PTR		' Does it matter?
        b		As DWORD
    End Type
    Thanks for any and all help!


    ------------------
    Mark Newman



    [This message has been edited by Mark Newman (edited March 16, 2001).]
    Mark Newman

  • #2
    A UINT is a DWORD. A DWORD is interchangeable with any pointer type, although
    there's no particularly good reason to prefer a DWORD when you can use the
    appropriate pointer type.

    ------------------
    Tom Hanlin
    PowerBASIC Staff

    Comment


    • #3
      The ABC123 is then used in a function prototype like this:
      Code:
      extern __declspec( dllimport ) HWND SomeFunction(ABC123);
      My translation is:
      Code:
      Declare Sub SomeFunction Lib "SomeLibrary.DLL" Alias "SomeFunction" (dwValue as DWORD)
      Would that not be:
      Code:
      Declare Function SomeFunction Lib "SomeLibrary.DLL" Alias "SomeFunction" (Byref dwValue as ABC123) as Long
      --
      Best Regards
      Peter Scheutz

      ------------------


      [This message has been edited by Peter Scheutz (edited March 17, 2001).]
      Best Regards
      Peter Scheutz

      Comment


      • #4
        Peter,

        Could well be! I have no idea. Well, it's not quite that bad.
        As I understand it, the original C code:

        typedef struct ABC123__ { int unused; } FAR* ABC123;

        defines a structure (consisting of the element 'unused') and then
        declares it as a far pointer. So my translation of the function
        call uses a DWORD as a pointer. But in looking at some sample C
        code that came with this DLL, it appears that your version could
        be correct. I guess I'll have to try them both and wait for the
        GPFs.



        ------------------
        Mark Newman
        Mark Newman

        Comment


        • #5
          Hi Mark

          It was just that the c declare
          extern __declspec( dllimport ) HWND SomeFunction(ABC123);

          returns a HWND and therefore should be a Function and not a Sub.

          --
          Peter

          ------------------
          Best Regards
          Peter Scheutz

          Comment


          • #6
            Peter,

            Ach! How did I miss that!

            Thanks very much for the help!


            ------------------
            Mark Newman
            Mark Newman

            Comment


            • #7
              Mark,

              There a lot of good C/C++ books on the market. Try one,
              you'll either like or dislike them. Anyway, a good way
              to learn C/C++. A necessity in learning PB for Windows
              since ALL of the MSDN stuff is in C.

              Cheers,
              Cecil

              ------------------

              Comment


              • #8
                Hi Cecil,

                I do have the K & R ANSI C book, which is a good solid reference but doesn't
                cover C++. I also have a dusty "DOS C Programmer's Reference" which comes
                in handy once in a while. So far, between these books, some C programmer
                friends, my own vague memories of C programming, and of course the very
                helpful folks here I've been able to work past these C issues.

                I really don't want to go back to C, but I might have to when I move
                from VB6 to .NET; can't decide if I should learn VB.NET or C#. But
                let's save that for another thread!



                ------------------
                Mark Newman
                Mark Newman

                Comment


                • #9
                  Hello

                  Well, I might be mistaken but I would translate the first
                  structure as:

                  TYPE ABC123_
                  unused AS LONG
                  END TYPE
                  DIM ABC123 AS ABC123_ PTR


                  'if you are going to use it in the function, you could declare it
                  'like this:
                  DIM ABC123 AS ABC123_


                  In the c code, the FAR* ABC123 just declares a variable for the
                  structure (TYPE in PB) ABC123_


                  The function should be declared like that:
                  DECLARE FUNCTION SomeFunction LIB "SomeLibrary.DLL" (ABC123 AS ABC123_) as LONG

                  What happens is that in C (not C++), if you want to pass a
                  parameter by reference, you pass a pointer to it.


                  I will try to explain this better. For example
                  PB:
                  FUNCTION AddOne(x AS LONG) AS LONG
                  x = x + 1
                  FUNCTION = x
                  END FUNCTION

                  In this example, x is passed by reference. The similar code in
                  c is

                  int AddOne(int *x)
                  {
                  *x = *x + 1;
                  return *x;
                  }
                  int A;
                  int B;
                  B = AddOne(&A);

                  In this case, x is a pointer to an integer.

                  In C++ you could write it like this:
                  int AddOne(int &x)
                  {
                  x = x + 1;
                  return x;
                  }
                  int A;
                  int B;

                  B = AddOne(A);


                  Much nicer and similar to PB

                  If this function were defined in
                  a DLL, there would be two options to declare it in PB
                  DECLARE FUNCTION AddOne LIB "SomeLib.dll" (BYVAL x as DWORD) as LONG

                  then I would call the function as:

                  A = 1
                  B = AddOne(CODEPTR(A))

                  A simpler and much better solution would be to declare
                  the function as:

                  DECLARE FUNCTION AddLone LIB "SomeLib.dll" (x AS LONG) AS LONG
                  In this case, PB actually passes the pointer to the variable.
                  This can be seen when you compare Windows API function declaration
                  written in PB and in C (Petzold's book)

                  'The linked list:
                  TYPE tag_AnItem
                  param1 AS DWORD
                  param2 as DWORD
                  param3 as DWORD
                  next AS tag_AnItem PTR
                  END TYPE

                  DIM AnItem AS tag_AnItem

                  'I think that you should always (at least when possible) use the
                  PTR declaration. It matters since if want to reference the value
                  if you don't declare the pointer with PTR, there is no way the
                  compiler knows how to reference, example:

                  DIM p AS DOUBLE PTR
                  'Allocate memory
                  ...
                  PRINT @p 'The compiler knows that @p is a DOUBLE

                  If instead,
                  DIM p AS DWORD
                  was used, the compiler wouldn't know how to reference the variable:
                  PRINT @p 'INTEGER, DOUBLE, etc???


                  I hope this helps.

                  ------------------

                  Comment


                  • #10
                    Thanks; more things to think about! I updated my code based upon
                    the information in your post; I missed the linked list item so
                    now that's fixed.

                    As to the ABC123__ structure, from some sample C source code it
                    seems that ABC123 isn't being used as a structure, but rather
                    as a pointer to a block of memory. But then why declare it as a
                    structure??? ABC123 is passed as a parameter to subs & functions
                    and also as a return type from a function. It's not clear if
                    the pointer itself is returned or a pointer to a pointer.

                    I'm starting to remember why I gave up C.

                    Such fun!

                    ------------------
                    Mark Newman

                    [This message has been edited by Mark Newman (edited March 20, 2001).]
                    Mark Newman

                    Comment


                    • #11
                      Once you understand how to use pointers, c/c++ is
                      very simple. In your code, ABC123 is declared as
                      FAR* ABC123, the '*' operator means that the variable
                      follwing is a pointer. When an argument of a function
                      is a pointer, this means that the variable is being
                      passed by reference (in PB it is equivalent to declaring
                      the variable WITHOUT the BYVAL keyword). When a function
                      returns a pointer, this is just a way to return some
                      sort of complex data type. This could be done in PB too.
                      It is just a way to do something like this (note that
                      this is not possible in PB or c, at least I think it is
                      possible):
                      TYPE Some_Type
                      Field1 AS ...
                      Field2 AS ...
                      ...
                      END TYPE

                      FUNCTION SomeFunc(...) AS Some_Type

                      ...
                      ...
                      END FUNCTION

                      Using a function that returns a pointer to a complex
                      data type is the closest you will get to a code as the
                      example above using PB or C.

                      Actually, using pointers is very useful when developing
                      data structures. For example: I'm writing a program to
                      solve fluid flow differential equations. This involves
                      solving *very* large systems of linear equations (some
                      systems might have 1 million equations!). Most of the
                      coefficients of the matrix is 0 and using sparse matrix
                      is essential. I'm using dynamic data strucures that does
                      heavy use of pointers to represent these matrices. At
                      the end, it is very simple (and readable) to use these
                      matrices. This program had to be written in C because
                      I'm going to execute it in Linux and UNIX workstations.

                      I hope this helps

                      Paulo


                      ------------------

                      Comment


                      • #12
                        Paulo,

                        Pointers I don't mind, but not when it's considered good C syntax to write code like this:

                        *#(*#)@*&<<..>>|=#@!&&!++&@@@**FAR** struct {whee};

                        Okay, I'm being a bit silly but you get my point.

                        As you said, PB doesn't support returning UDTs from a function directly in code,
                        so I've changed all of the DECLAREs to return a DWORD pointer instead, which so
                        far is working at a 50% success rate: The functions return 'success' codes but
                        I'm getting GPFs later on. Hmmm.

                        Pointers are a very useful tool, and like most such tools are prone to overuse/abuse. Back when I did C programming (DOS) I was using
                        a 3rd-party user interface C library for creating and running the user interface. All was fine until I wanted to change one of the
                        default behaviours, which required that I look at the header files of the library. I found the variable that I needed to change right
                        away, but oops, it's a pointer to another variable in another header file. I found that one, again to find that it was a pointer to
                        yet another variable in yet another header file. SIX levels of indirection later I still hadn't found the variable I was looking for,
                        so I quietly closed the manuals, closed the editor, took the books and disks to the department junkyard and threw them in. I switched
                        to MS PDS 7.1 and haven't written a line of C code since!




                        ------------------
                        Mark Newman
                        Mark Newman

                        Comment


                        • #13
                          Returning a pointer to a UDT is only going to work if the target is not local in scope to the sub/function returning the pointer!

                          That is, by the time the pointer is returned to the calling code, the memory ocupied by the pointer's target has been released back to the system pool. The solution is to allocate the UDT storage as GLOBAL or STATIC so it stays persistent after the sub/function terminates.


                          ------------------
                          Lance
                          PowerBASIC Support
                          mailto:[email protected][email protected]</A>
                          Lance
                          mailto:[email protected]

                          Comment


                          • #14
                            The UDT variables and many object handles are already GLOBAL,
                            thanks just the same. No success yet, unfortunately.


                            ------------------
                            Mark Newman
                            Mark Newman

                            Comment

                            Working...
                            X