Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #145696 > unrolled thread

Calling a machine code/binary function given its address, return type, & parameter types

Started byDavid Williams <dwilliams1664@gmail.com>
First post2019-08-17 06:58 -0700
Last post2019-08-21 09:05 -0400
Articles 14 — 8 participants

Back to article view | Back to comp.lang.c


Contents

  Calling a machine code/binary function given its address, return type, & parameter types David Williams <dwilliams1664@gmail.com> - 2019-08-17 06:58 -0700
    Re: Calling a machine code/binary function given its address, return type, & parameter types Richard Damon <Richard@Damon-Family.org> - 2019-08-17 10:14 -0400
    Re: Calling a machine code/binary function given its address, return type, & parameter types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-08-17 07:17 -0700
    Re: Calling a machine code/binary function given its address, return type, & parameter types Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-08-17 15:26 +0100
    Re: Calling a machine code/binary function given its address, return type, & parameter types Siri Cruise <chine.bleu@yahoo.com> - 2019-08-17 12:15 -0700
    Re: Calling a machine code/binary function given its address, return type, & parameter types Bart <bc@freeuk.com> - 2019-08-17 20:34 +0100
      Re: Calling a machine code/binary function given its address, return type, & parameter types Keith Thompson <kst-u@mib.org> - 2019-08-17 14:31 -0700
    Re: Calling a machine code/binary function given its address, return type, & parameter types Keith Thompson <kst-u@mib.org> - 2019-08-17 15:10 -0700
      Re: Calling a machine code/binary function given its address, return type, & parameter types Richard Damon <Richard@Damon-Family.org> - 2019-08-17 20:09 -0400
        Re: Calling a machine code/binary function given its address, return type, & parameter types Keith Thompson <kst-u@mib.org> - 2019-08-17 17:54 -0700
    Re: Calling a machine code/binary function given its address, return type, & parameter types David Williams <dwilliams1664@gmail.com> - 2019-08-18 09:57 -0700
      Re: Calling a machine code/binary function given its address, return type, & parameter types Bart <bc@freeuk.com> - 2019-08-18 18:37 +0100
      Re: Calling a machine code/binary function given its address, return type, & parameter types Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-08-18 21:40 +0100
      Re: Calling a machine code/binary function given its address, return type, & parameter types James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-08-21 09:05 -0400

#145696 — Calling a machine code/binary function given its address, return type, & parameter types

FromDavid Williams <dwilliams1664@gmail.com>
Date2019-08-17 06:58 -0700
SubjectCalling a machine code/binary function given its address, return type, & parameter types
Message-ID<66319c70-be79-466d-ba04-f8bb1b2d3a8a@googlegroups.com>
I have the address of a function that has already been compiled (so it's now effectively a machine code routine that I've loaded into memory and for which I have obtained the address). I pass this address by value as a parameter (long or uint64_t) to my C subroutine. I know the return type of the function (int), and that it takes 4 parameters (ptr, ptr, const ptr, const ptr). How do I call this function from my C subroutine?

I have Googled about function pointers, and I've noticed that others have asked a similar question, but the answers they received somehow don't seem directly applicable to my requirement. In any case, I've had no joy in my attempts at getting my (test) C subroutine to compile without errors. I obviously still have a weak grasp of C pointers and function pointers (although I'm learning!).

The platform is 64-bit Linux (x86-64).


Regards,
David.




[toc] | [next] | [standalone]


#145697

FromRichard Damon <Richard@Damon-Family.org>
Date2019-08-17 10:14 -0400
Message-ID<mZT5F.193$423.30@fx07.iad>
In reply to#145696
On 8/17/19 9:58 AM, David Williams wrote:
> I have the address of a function that has already been compiled (so it's now effectively a machine code routine that I've loaded into memory and for which I have obtained the address). I pass this address by value as a parameter (long or uint64_t) to my C subroutine. I know the return type of the function (int), and that it takes 4 parameters (ptr, ptr, const ptr, const ptr). How do I call this function from my C subroutine?
> 
> I have Googled about function pointers, and I've noticed that others have asked a similar question, but the answers they received somehow don't seem directly applicable to my requirement. In any case, I've had no joy in my attempts at getting my (test) C subroutine to compile without errors. I obviously still have a weak grasp of C pointers and function pointers (although I'm learning!).
> 
> The platform is 64-bit Linux (x86-64).
> 
> 
> Regards,
> David.
> 

We can declair the function pointer you need as:

int (*funcp)(void*, void*, const void*, const void*)

(You haven't defined what types of pointer you have, so I have used
void*, you really should define the pointer with the right types, but
for x86-64 all object pointer types have the same representation so it
might not cause a real issue).

You can make that function pointer point to your function with a
statement like:

  funcp = (int (*)(void*, void*, const void*, const void*))(addr);

Note, this is implementation defined on how it exactly works, but if
addr is a 64 bit intergral value, for x86-64 this should work.

You can then call the function through that pointer as

   result = funcp(ptr1, ptr2, cptr3, cptr4);

It is possible to wrap all this up into a single statement, (casting the
value into a function pointer type and then calling that function
through the just created function pointer value) but it is clearer doing
it in steps.

[toc] | [prev] | [next] | [standalone]


#145698

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2019-08-17 07:17 -0700
Message-ID<725aa3a9-88ea-4de3-9393-3eec76fd8622@googlegroups.com>
In reply to#145696
On Saturday, 17 August 2019 14:58:43 UTC+1, David Williams  wrote:
> I have the address of a function that has already been compiled 
> (so it's now effectively a machine code routine that I've loaded 
> into memory and for which I have obtained the address). I pass this
> address by value as a parameter (long or uint64_t) to my C subroutine.
> I know the return type of the function (int), and that it takes 4
> parameters (ptr, ptr, const ptr, const ptr). How do I call this 
> function from my C subroutine?
> 
> I have Googled about function pointers, and I've noticed that 
> others have asked a similar question, but the answers they received
> somehow don't seem directly applicable to my requirement. In any case,
> I've had no joy in my attempts at getting my (test) C subroutine to
> compile without errors. I obviously still have a weak grasp of C pointers > and function pointers (although I'm learning!).
> 
> The platform is 64-bit Linux (x86-64).
> 
C's syntax for function pointers is awful, though the concept is quite
simple. A function pointer is the address of a machine code routine,
with return type and parameters defined in its type;
Your type is

int (*functionpointer)(void *, void *, const void *, const void *)

(The parameters might not be void *s, you don't give information
on what they point to. void *s will work but be less safe and self-
documenting).

Now it is easiest to typedef before casting to that function pointer
type, else the syntax becomes horrendeous.

So

typedef int (*functionpoiintertype)(void *, void *, const void *, const void *);

This is a bit counter-intuitive, but it creates a type called "functionpointertype" of the right type.

Now your address will be passed in as an inteter, call it intaddress

void caller(unit64_t intaddress)
{
   /* cast it */
   functionpointertype myfunctionpointer = (functionpointertype) intaddress;

   /* now call it, I've put in dummy parameters */

   myfunctionpointer(0, 0, 0, 0);
} 



 


[toc] | [prev] | [next] | [standalone]


#145699

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-08-17 15:26 +0100
Message-ID<87v9uvc1g7.fsf@bsb.me.uk>
In reply to#145696
David Williams <dwilliams1664@gmail.com> writes:

> I have the address of a function that has already been compiled (so
> it's now effectively a machine code routine that I've loaded into
> memory and for which I have obtained the address). I pass this address
> by value as a parameter (long or uint64_t) to my C subroutine.

If you can, it would be better to pass the address as a function
pointer.  You can use any function pointer type, but since you know the
type, why not use that?

> I know
> the return type of the function (int), and that it takes 4 parameters
> (ptr, ptr, const ptr, const ptr). How do I call this function from my
> C subroutine?

Do you know the actual types?  If not, you may get away it, but you won't
have portable or "correct" C.

By "const ptr" I assume you mean the /target/ of the pointer is a
const-qualified type (otherwise the const is not really important for
getting the call right), so let's assume that the actual types are void
*, int *, const void * and const int *.  With that in mind, your
function might look like this:

  void do_call(uint64_t func_addr, /* ... more arguments ... */)
  {
      typedef int function_type(void *, int *, const void *, const int *);
      function_type *fp = (function_type *)func_addr;
      int result = fp(/* ... actual arguments ... */);

      /* ... more code ... */
  }

Of course you can do this without the typedef and/or without the extra
variable fp, but the syntax gets hairy.  Note that I prefer to define
the function type and then write a * explicitly when I want a pointer to
a function of that type.

Going back to my comment about using the right type to start with, I'd
do this if possible:

  typedef int function_type(void *, int *, const void *, const int *);

  void do_call(function_type *fp, /* ... more arguments ... */)
  {
      int result = fp(/* ... actual arguments ... */);

      /* ... more code ... */
  }

and, if you have to, cast the uint64_t to a function_type * at the point
where you call do_call.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#145700

FromSiri Cruise <chine.bleu@yahoo.com>
Date2019-08-17 12:15 -0700
Message-ID<chine.bleu-678C3E.12153817082019@reader.eternal-september.org>
In reply to#145696
In article <66319c70-be79-466d-ba04-f8bb1b2d3a8a@googlegroups.com>,
 David Williams <dwilliams1664@gmail.com> wrote:

> I have the address of a function that has already been compiled (so it's now 
> effectively a machine code routine that I've loaded into memory and for which 
> I have obtained the address). I pass this address by value as a parameter 
> (long or uint64_t) to my C subroutine. I know the return type of the function 
> (int), and that it takes 4 parameters (ptr, ptr, const ptr, const ptr). How 
> do I call this function from my C subroutine?

I would be inclined to add a function prototype declaration in c and define the 
function name as the address in the linker. Or equivalently do a short assembly 
file that merely defines the function name as an external symbol to the known 
address.

-- 
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted.    @
'I desire mercy, not sacrifice.'                                    /|\
The first law of discordiamism: The more energy   This post         / \
to make order is nore energy made into entropy.   insults Islam.  Mohammed

[toc] | [prev] | [next] | [standalone]


#145701

FromBart <bc@freeuk.com>
Date2019-08-17 20:34 +0100
Message-ID<%EY5F.44947$665.27757@fx28.am4>
In reply to#145696
On 17/08/2019 14:58, David Williams wrote:
> I have the address of a function that has already been compiled (so it's now effectively a machine code routine that I've loaded into memory and for which I have obtained the address). I pass this address by value as a parameter (long or uint64_t) to my C subroutine. I know the return type of the function (int), and that it takes 4 parameters (ptr, ptr, const ptr, const ptr). How do I call this function from my C subroutine?
> 
> I have Googled about function pointers, and I've noticed that others have asked a similar question, but the answers they received somehow don't seem directly applicable to my requirement. In any case, I've had no joy in my attempts at getting my (test) C subroutine to compile without errors. I obviously still have a weak grasp of C pointers and function pointers (although I'm learning!).
> 
> The platform is 64-bit Linux (x86-64).

What code did you try, and with which compiler?

C allows functions and function pointers to be declared withour 
specifying the number and types of the parameters. Example:

     #include <stdio.h>

     int(*fnptr)();

     int main(void) {
         int result;

         result = fnptr(NULL,NULL,NULL,NULL);
     }


Since you say it takes four pointers, four pointers (in the form of 
zeros or NULLs) have been supplied.

But it would be much better if the actual parameter types, if known, 
were provided, as then more checking can be done. For example:

     int(*fnptr)(int*, float*, char*, char*);

You can put 'const' in there too (I assume the const applies to what the 
pointer points to, so would be written as 'const char*'), but it usually 
doesn't matter (some people have a bee in the bonnet about using 'const' 
at every opportunity).

BTW has the machine code routine be written in C too, or in a HLL? If 
not, then for x64 it would need to have been written using the correct 
ABI (the mechanics of how parameters are passed and values returned).

[toc] | [prev] | [next] | [standalone]


#145703

FromKeith Thompson <kst-u@mib.org>
Date2019-08-17 14:31 -0700
Message-ID<lna7c75vhu.fsf@kst-u.example.com>
In reply to#145701
Bart <bc@freeuk.com> writes:
> On 17/08/2019 14:58, David Williams wrote:
>> I have the address of a function that has already been compiled (so
>> it's now effectively a machine code routine that I've loaded into
>> memory and for which I have obtained the address). I pass this
>> address by value as a parameter (long or uint64_t) to my C
>> subroutine. I know the return type of the function (int), and that it
>> takes 4 parameters (ptr, ptr, const ptr, const ptr). How do I call
>> this function from my C subroutine?
>> 
>> I have Googled about function pointers, and I've noticed that others
>> have asked a similar question, but the answers they received somehow
>> don't seem directly applicable to my requirement. In any case, I've
>> had no joy in my attempts at getting my (test) C subroutine to
>> compile without errors. I obviously still have a weak grasp of C
>> pointers and function pointers (although I'm learning!).
>> 
>> The platform is 64-bit Linux (x86-64).
>
> What code did you try, and with which compiler?
>
> C allows functions and function pointers to be declared withour 
> specifying the number and types of the parameters. Example:
>
>      #include <stdio.h>
>
>      int(*fnptr)();
>
>      int main(void) {
>          int result;
>
>          result = fnptr(NULL,NULL,NULL,NULL);
>      }
> 
> Since you say it takes four pointers, four pointers (in the form of 
> zeros or NULLs) have been supplied.

NULL is a macro that expands to a null pointer constant, but a null
pointer constant isn't necessarily of pointer type.  (Yes, that's weird
and counterintuitive, but it's true.)  A null pointer constant yields a
null pointer value when it's converted to a pointer type.  If you call a
function with no prototype, no such conversion is done.

If, for example, NULL is defined as 0, int is 32 bits, and pointers are
64 bits, then fnptr(NULL,NULL,NULL,NULL) will pass 4 32-bit integer
values to a function that presumably expects 4 64-bit pointer values.

I *hope* that the actual types of the four parameters are known.  If
that's the case, then declare the function type (or, if you insist,
the function pointer type) with a prototype that specifies those
parameter types.  With a visible prototype, NULL will be implicitly
converted to the correct type.

In the unlikely event that you really need to use an old-style
non-prototype declaration, and you're willing to assume that all object
pointers are interchangeable, then cast the NULL arguments to void*:

    result = fnptr((void*)NULL, (void*)NULL, (void*)NULL, (void*)NULL);

But if you know the actual types, then old-style non-prototype
declarations are a can of worms you don't need to open.

(The OP didn't say that the arguments should be null pointers, so it's
likely that the NULL stuff is irrelevant.)


> But it would be much better if the actual parameter types, if known, 
> were provided, as then more checking can be done. For example:
>
>      int(*fnptr)(int*, float*, char*, char*);

Yes.

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#145705

FromKeith Thompson <kst-u@mib.org>
Date2019-08-17 15:10 -0700
Message-ID<ln5zmv5tpo.fsf@kst-u.example.com>
In reply to#145696
David Williams <dwilliams1664@gmail.com> writes:
> I have the address of a function that has already been compiled (so
> it's now effectively a machine code routine that I've loaded into
> memory and for which I have obtained the address). I pass this address
> by value as a parameter (long or uint64_t) to my C subroutine. I know
> the return type of the function (int), and that it takes 4 parameters
> (ptr, ptr, const ptr, const ptr). How do I call this function from my
> C subroutine?
>
> I have Googled about function pointers, and I've noticed that others
> have asked a similar question, but the answers they received somehow
> don't seem directly applicable to my requirement. In any case, I've
> had no joy in my attempts at getting my (test) C subroutine to compile
> without errors. I obviously still have a weak grasp of C pointers and
> function pointers (although I'm learning!).
>
> The platform is 64-bit Linux (x86-64).

Others have discussed how you can do this *if it can be done*.  But
there is no way to do this in portable C.  But since you're dealing with
calling machine code routines, you're probably not too concerned about
portability.

Do you know the actual types of the four parameters, or do you only know
that they're pointers?  Knowing their actual types is going to make this
easier.

If you could get the address of the machine code routine *as a function
pointer value* rather than as an integer, that's also going to help,
since you can call it directly via the function pointer.  If it has to
be an integer, using uintptr_t (defined in <stdint.h>) would be a bit
cleaner, since that integer type is specified to be able to hold
converted pointer values.

If you aren't starting with a function pointer, converting to a function
pointer is tricky.  (We've had some long boring discussions here about
whether converting from an object pointer to a function pointer is
"illegal" or merely has undefined behavior.)  The only way this might
affect you is that if you're using gcc with options that tell it to
strictly enforce the language rules (e.g., "gcc -std=c11 -pedantic" or
"gcc -std=c11 -pedantic-errors") you might get a warning or error
message about the conversion.

Having said all that, here's an outline of something that's likely to
work.  (It compiles, but blows up when I run it because I'm not using a
valid function address.)

#include <stdint.h>

const uintptr_t the_address = 0xDEADBEEF;
// or whatever the address is, and however you got it

int call_the_function(uintptr_t addr, void *arg1, void *arg2, const void
*arg3, const void *arg4) {
    // Define the type of the called function
    typedef int(func)(void*, void*, const void*, const void*);

    // Construct a pointer to the function
    func *fptr = (func*)addr;

    // and call it
    return fptr(arg1, arg2, arg3, arg4);
}

int main(void) {
    // Declare the arguments
    // Hopefully they'll have more specific pointer types,
    // and you'll have values for them.
    void *arg1;
    void *arg2;
    const void *arg3;
    const void *arg4;
    int result = call_the_function(the_address, arg1, arg2, arg3, arg4);
}

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#145706

FromRichard Damon <Richard@Damon-Family.org>
Date2019-08-17 20:09 -0400
Message-ID<kH06F.12371$9i3.9733@fx42.iad>
In reply to#145705
On 8/17/19 6:10 PM, Keith Thompson wrote:
> David Williams <dwilliams1664@gmail.com> writes:
...
>> The platform is 64-bit Linux (x86-64).
> 
> Others have discussed how you can do this *if it can be done*.  But
> there is no way to do this in portable C.  But since you're dealing with
> calling machine code routines, you're probably not too concerned about
> portability.
> 

Actually, since he knows the platform and that has been specified, he
probably only really needs portable on that platform. I am pretty sure
the ABI for that platform says that uintptr_t will exist and alias the
same type as uint64_t which I think is unsigned long long (not as sure
on that last point).

I am also pretty sure that the platform ABI will define how casting that
type to a function pointer will work (Linux has needs for that operation
for things like share libraries, so they will define how it should work).

Given that, assuming he is using a proper compiler for the environment,
it should work.

[toc] | [prev] | [next] | [standalone]


#145707

FromKeith Thompson <kst-u@mib.org>
Date2019-08-17 17:54 -0700
Message-ID<lno90n47kn.fsf@kst-u.example.com>
In reply to#145706
Richard Damon <Richard@Damon-Family.org> writes:
> On 8/17/19 6:10 PM, Keith Thompson wrote:
>> David Williams <dwilliams1664@gmail.com> writes:
> ...
>>> The platform is 64-bit Linux (x86-64).
>> 
>> Others have discussed how you can do this *if it can be done*.  But
>> there is no way to do this in portable C.  But since you're dealing with
>> calling machine code routines, you're probably not too concerned about
>> portability.
>
> Actually, since he knows the platform and that has been specified, he
> probably only really needs portable on that platform. I am pretty sure
> the ABI for that platform says that uintptr_t will exist and alias the
> same type as uint64_t which I think is unsigned long long (not as sure
> on that last point).

Sure -- but if the OP really needs to use an integer type to represent a
pointer value, using uintptr_t makes the code clearer.

I often find that portable code is clearer than non-portable code, even
if portability is not a concern.  (Often, not always.)

> I am also pretty sure that the platform ABI will define how casting that
> type to a function pointer will work (Linux has needs for that operation
> for things like share libraries, so they will define how it should work).
>
> Given that, assuming he is using a proper compiler for the environment,
> it should work.

Agreed.  See POSIX dlsym(), for example, which assumes you can can
convert a void* to a function pointer.  But if you need to convert void*
to a function pointer type, you should at least be aware that gcc will
complain about it *if* you use certain options.  (It also doesn't hurt
to be aware that, at the very least, the C standard doesn't define the
behavior.)

Some of these issues don't apply to converting an integer to a function
pointer.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#145715

FromDavid Williams <dwilliams1664@gmail.com>
Date2019-08-18 09:57 -0700
Message-ID<dd916477-94df-43aa-a31f-5dd7c4613a1f@googlegroups.com>
In reply to#145696
Thank you to everyone who replied to my query, it's much appreciated.

The first (and admittedly so far, only) solution I tried was Richard Damon's, and my tiny 'test harness' C program compiled happily without complaint the first time. I was very pleased! I will study all of the suggestions, and endeavour to understand them (rather than just greedily grab & run with Richard's one).   

I didn't state the pointer types in my original post because all four of them are composite types. The specific function that I wanted to call was actually an SDL 2.0 function called SDL_RenderCopy:

https://wiki.libsdl.org/SDL_RenderCopy

I knew that the four parameters it takes would equate to 64-bit memory addresses on my system (64-bit Linux Mint running on an Intel Core i7, the compiler being GCC 7.4.0). Currently, there is no requirement for my code to be portable (since I'm the only one running it!).

Anyway, I made a very quick demo (written in novice-quality C, compiled to a shared library (.so)), which was subsequently loaded/imported by a HLL (BASIC, in this case)). I then call my compiled C routine from BASIC, passing to it the address of SDL_RenderCopy (30-second video):

https://youtu.be/MiM_le1Lsdg
 
Again, thanks to everyone for their suggestions and advice. 


David,
England.
--

  

[toc] | [prev] | [next] | [standalone]


#145716

FromBart <bc@freeuk.com>
Date2019-08-18 18:37 +0100
Message-ID<11g6F.94891$RU2.79615@fx21.am4>
In reply to#145715
On 18/08/2019 17:57, David Williams wrote:
> Thank you to everyone who replied to my query, it's much appreciated.
> 
> The first (and admittedly so far, only) solution I tried was Richard Damon's, and my tiny 'test harness' C program compiled happily without complaint the first time. I was very pleased! I will study all of the suggestions, and endeavour to understand them (rather than just greedily grab & run with Richard's one).
> 
> I didn't state the pointer types in my original post because all four of them are composite types. The specific function that I wanted to call was actually an SDL 2.0 function called SDL_RenderCopy:
> 
> https://wiki.libsdl.org/SDL_RenderCopy
> 
> I knew that the four parameters it takes would equate to 64-bit memory addresses on my system (64-bit Linux Mint running on an Intel Core i7, the compiler being GCC 7.4.0). Currently, there is no requirement for my code to be portable (since I'm the only one running it!).

This doesn't make things any clearer! Actually it is now much more 
confusing.

(Is RenderCopy directly called from the DLL-ed C code? If not, why not? 
Where does BASIC object the address of RenderCopy from? Note that this 
function's address can be obtained in C (when you can't simply use 
"sdl.h" in the normal manner), like this:

   #include <stdio.h>
   #include <windows.h>
   int main(void) {
     HANDLE hinst;
     void(*fnptr)(void);    // here specified with 0 params

     hinst=LoadLibrary("/sdl/sdl2");   // path on my machine

     printf("HINST = %p\n",hinst);

     fnptr=GetProcAddress(hinst,"SDL_RenderCopy");

     printf("FNPTR = %p\n",fnptr);
   }
)

Anyway, good to hear your program is now running.

[toc] | [prev] | [next] | [standalone]


#145719

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2019-08-18 21:40 +0100
Message-ID<87k1bab411.fsf@bsb.me.uk>
In reply to#145715
David Williams <dwilliams1664@gmail.com> writes:

> I didn't state the pointer types in my original post because all four
> of them are composite types.

A heads up: composite type is a technical term in C and none of your
function's parameters are composite types as C uses the term.

> The specific function that I wanted to call was actually an SDL 2.0
> function called SDL_RenderCopy:
>
> https://wiki.libsdl.org/SDL_RenderCopy

You could have given those types -- too much information is usually
better than too little.  I think by composite types you mean what C
calls aggregate (or more specifically struct) types.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#145745

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2019-08-21 09:05 -0400
Message-ID<qjjfie$3s5$1@dont-email.me>
In reply to#145715
On 8/18/19 12:57 PM, David Williams wrote:
> Thank you to everyone who replied to my query, it's much appreciated.
> 
> The first (and admittedly so far, only) solution I tried was Richard Damon's, and my tiny 'test harness' C program compiled happily without complaint the first time. I was very pleased! I will study all of the suggestions, and endeavour to understand them (rather than just greedily grab & run with Richard's one).   
> 
> I didn't state the pointer types in my original post because all four of them are composite types. The specific function that I wanted to call was actually an SDL 2.0 function called SDL_RenderCopy:
> 
> https://wiki.libsdl.org/SDL_RenderCopy
> 
> I knew that the four parameters it takes would equate to 64-bit memory addresses on my system (64-bit Linux Mint running on an Intel Core i7, the compiler being GCC 7.4.0). Currently, there is no requirement for my code to be portable (since I'm the only one running it!).
> 
> Anyway, I made a very quick demo (written in novice-quality C, compiled to a shared library (.so)), which was subsequently loaded/imported by a HLL (BASIC, in this case)). I then call my compiled C routine from BASIC, passing to it the address of SDL_RenderCopy (30-second video):
> 
> https://youtu.be/MiM_le1Lsdg

If your code worked, it's probably OK, but it's generally better, when
writing C code, to tell it the correct types for things rather than
lying and hoping that the lie works. Here's how to tell it the truth:

#include "SDL.h"
typedef int SDL_RenderCopy_type (SDL_Renderer*, SDL_Texture*,
    const SDL_Rect*, const SDL_Rect*)
// Note: SDL.h declares SDL_RenderCopy as a function so you
// can't re-use that name as a function pointer. If you could
// count on the linker to resolve that identifier correctly,
// you obviously wouldn't be doing this. Therefore, you'll
// have to rename your pointer:

SDL_RenderCopy_type *SDL_RenderCopy_ptr =
   (SDL_RenderCopy_type*)pSDL_RenderCopy;

As far as portable code is concerned, that conversion has undefined
behavior - but if your code actually worked, your implementation has
apparently defined the behavior in such a way that this conversion is
also likely to work. Just use SDLRenderCopy_ptr instead of
SDL_RenderCopy in your subsequent code.

It's been four decades since I last programmed in BASIC, what little I
still remember about it is obviously obsolete (the version I learned
limited variable names to one character in length). Therefore, I have no
idea how it's interface with C works. However, it's entirely possible
that you could declare pSDL_RenderCopy itself as having the type
SDL_RenderCopy_type*, rather than long*, using one less variable and one
less type conversion.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web