Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #145696 > unrolled thread
| Started by | David Williams <dwilliams1664@gmail.com> |
|---|---|
| First post | 2019-08-17 06:58 -0700 |
| Last post | 2019-08-21 09:05 -0400 |
| Articles | 14 — 8 participants |
Back to article view | Back to comp.lang.c
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
| From | David Williams <dwilliams1664@gmail.com> |
|---|---|
| Date | 2019-08-17 06:58 -0700 |
| Subject | Calling 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]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2019-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]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2019-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-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]
| From | Siri Cruise <chine.bleu@yahoo.com> |
|---|---|
| Date | 2019-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]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-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]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2019-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-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]
| From | David Williams <dwilliams1664@gmail.com> |
|---|---|
| Date | 2019-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]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-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]
| From | James Kuyper <jameskuyper@alumni.caltech.edu> |
|---|---|
| Date | 2019-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