Lazarus

Free Pascal => General => Topic started by: jiaxing2 on May 12, 2020, 07:34:34 pm

Title: How to translate typedef void * to Pascal?
Post by: jiaxing2 on May 12, 2020, 07:34:34 pm
Example: typedef void *my_annoying_c_function(size_t sz);
Title: Re: How to translate typedef void * to Pascal?
Post by: JdeHaan on May 12, 2020, 07:57:08 pm
type
  TMy_Annoying_C_Function = procedure(sz: QWord);
Title: Re: How to translate typedef void * to Pascal?
Post by: jamie on May 12, 2020, 08:01:29 pm
Normally the compiler settings are set so that u can use a function like void. The code ignores the return.
But if want a cleaner code base with less unneeded background code the use a procedure, which is the same basically.
Title: Re: How to translate typedef void * to Pascal?
Post by: Thaddy on May 12, 2020, 08:27:21 pm
as jdehaan wrote typedef void * functions (literary ignore/don't use a result) indicates the same as a Pascal procedure, and although there are pascal modes that can ignore a Pascal function result, so in fact like a procedure, this is not quite the same: such code still assigns a result because the compiler can not know if another call uses the result and therefor a procedure is more efficient in such case. C works the same in the case of void * function.. it is C's haphazard notation for procedure..

jamie's answer is not correct. jdehaan's answer is correct.
It is all about the generated assembler and you can easily verify that.
Title: Re: How to translate typedef void * to Pascal?
Post by: 440bx on May 12, 2020, 09:04:43 pm
It's probably worth noting that size_t isn't qword.
Title: Re: How to translate typedef void * to Pascal?
Post by: Thaddy on May 12, 2020, 09:05:37 pm
It's probably worth noting that size_t isn't qword.
Well spotted!
But the documentation lacks here. File a report against documentation.
See https://www.freepascal.org/docs-html/rtl/unixtype/size_t.html
It does not explain size_t is platform. E.g on 32 bit it is cuint which in turn is an alias for a pointer size of dword.
So the mistake is easy to make. Note the compiler behaves properly.
size_t is ptruint/nativeuint.

type
  TMy_Annoying_C_Function = procedure(sz: nativeuint); // or more fpc, ptruint

Or:
uses unixtypes;
type
  TMy_Annoying_C_Function = procedure(sz: size_t);
Title: Re: How to translate typedef void * to Pascal?
Post by: tetrastes on May 12, 2020, 09:54:40 pm
Then how to translate
Code: C  [Select][+][-]
  1. typedef void my_annoying_c_function(size_t sz);
  2.  
Title: Re: How to translate typedef void * to Pascal?
Post by: jamie on May 12, 2020, 11:00:56 pm
as jdehaan wrote typedef void * functions (literary ignore/don't use a result) indicates the same as a Pascal procedure, and although there are pascal modes that can ignore a Pascal function result, so in fact like a procedure, this is not quite the same: such code still assigns a result because the compiler can not know if another call uses the result and therefor a procedure is more efficient in such case. C works the same in the case of void * function.. it is C's haphazard notation for procedure..

jamie's answer is not correct. jdehaan's answer is correct.
It is all about the generated assembler and you can easily verify that.

And Please explain to me where I am incorrect?

 You are a piece of work Thaddy in your own mind!

Title: Re: How to translate typedef void * to Pascal?
Post by: PascalDragon on May 13, 2020, 09:32:24 am
as jdehaan wrote typedef void * functions (literary ignore/don't use a result) indicates the same as a Pascal procedure, and although there are pascal modes that can ignore a Pascal function result, so in fact like a procedure, this is not quite the same: such code still assigns a result because the compiler can not know if another call uses the result and therefor a procedure is more efficient in such case. C works the same in the case of void * function.. it is C's haphazard notation for procedure..

jamie's answer is not correct. jdehaan's answer is correct.
It is all about the generated assembler and you can easily verify that.

And Please explain to me where I am incorrect?

 You are a piece of work Thaddy in your own mind!

Thaddy is right however. The declaration that jiaxing2 posted is essentially parsed like this:

Code: C  [Select][+][-]
  1. typedef void (*my_annoying_c_function)(size_t sz);

The correct translation of a C function having void as result type is to use a procedure. If you'd use a function the compiler would need to discard the result value (in most cases that is simply a register, but that doesn't have to be the case on all platforms) while for a procedure it doesn't need to do that, because it knows that there isn't one. Also if you'd implement a function that you'd assign to such a function variable you'd have do deal with Result while it wouldn't require one.

Then how to translate
Code: C  [Select][+][-]
  1. typedef void my_annoying_c_function(size_t sz);
  2.  


In the end those are used like this:

Code: C  [Select][+][-]
  1. my_annoying_c_function *func;

Thus you translate them just as if they were a normal function pointer, because Pascal doesn't have that distinction.
Title: Re: How to translate typedef void * to Pascal?
Post by: Thaddy on May 13, 2020, 12:07:38 pm
And Please explain to me where I am incorrect?
I did: the code generation differs between a function and a procedure. typedef void * is optimized by a C compiler in the same way as a Pascal procedure and a both do not have to account for a return value.
Even if  you can call a Pascal  function as a procedure, that function contains code for the return value, e.g. although you can it is not as efficient.
I reprhase wrong in not complete, because it lacks essental information as I described.
Title: Re: How to translate typedef void * to Pascal?
Post by: tetrastes on May 13, 2020, 12:11:24 pm

Thaddy is right however. The declaration that jiaxing2 posted is essentially parsed like this:

Code: C  [Select][+][-]
  1. typedef void (*my_annoying_c_function)(size_t sz);


Really? So
Code: C  [Select][+][-]
  1. void *malloc(size_t size);
returns nothing?

And
Code: C  [Select][+][-]
  1. char *strcpy(char *dest, const char *src);
is parsed like
Code: C  [Select][+][-]
  1. char (*strcpy)(char *dest, const char *src);
and returns one char, not c-style string?

Quote
Then how to translate
Code: C  [Select][+][-]
  1. typedef void my_annoying_c_function(size_t sz);
  2.  


In the end those are used like this:

Code: C  [Select][+][-]
  1. my_annoying_c_function *func;

Thus you translate them just as if they were a normal function pointer, because Pascal doesn't have that distinction.

Where does pointer arrive from? Sorry, I misunderstood you.
I mean that the code without pointer
Code: C  [Select][+][-]
  1. typedef void my_annoying_c_function(size_t sz);
  2.  
  3. my_annoying_c_function func;
is absolutely legal.
Title: Re: How to translate typedef void * to Pascal?
Post by: Thaddy on May 13, 2020, 12:25:22 pm
The pointer is simply the immediate address of the function itself, not a return value.
Title: Re: How to translate typedef void * to Pascal?
Post by: jiaxing2 on May 13, 2020, 01:24:28 pm
So it's because C doesn't has procedure like Pascal so they used a trick to workaround the limitation? Could I just replace it with a Pascal procedure?

Why don't they have to go through typedef and not use void in the place? I think C's void function is equivalent to Pascal's procedure.

p/s: I found this: https://www.geeksforgeeks.org/return-void-functions-c/ So C's void function could return something too.
Title: Re: How to translate typedef void * to Pascal?
Post by: Warfley on May 13, 2020, 01:30:42 pm
typedef void *my_annoying_c_function(size_t sz);
This is confusing, because who ever wrote that c code has forgotten the bracketing. Because there is a big difference between these two possibilities to bracket:
Code: C  [Select][+][-]
  1. typedef void *(my_annoying_c_function)(size_t sz);
which is a function returning a void pointer (i.e. the type Pointer in pascal)
or
Code: C  [Select][+][-]
  1. typedef void (*my_annoying_c_function)(size_t sz);
which is a pointer to a returnless function (i.e. pascal procedure)

The implicit bracketing of the function you've given is the first one, i.e. it is a function returning an untyped pointer, not a procedure. So the correct pascal implementation would be:
Code: Pascal  [Select][+][-]
  1. type my_annoying_c_function = function(sz: SizeInt): Pointer;
Title: Re: How to translate typedef void * to Pascal?
Post by: PascalDragon on May 13, 2020, 01:37:29 pm
And Please explain to me where I am incorrect?
I did: the code generation differs between a function and a procedure. typedef void * is optimized by a C compiler in the same way as a Pascal procedure and a both do not have to account for a return value.

You mean void, not void*. The * in the example is simply the notation for function pointer. A function pointer to a function returning a void* would be void* *func().


Thaddy is right however. The declaration that jiaxing2 posted is essentially parsed like this:

Code: C  [Select][+][-]
  1. typedef void (*my_annoying_c_function)(size_t sz);


Really? So
Code: C  [Select][+][-]
  1. void *malloc(size_t size);
returns nothing?

And
Code: C  [Select][+][-]
  1. char *strcpy(char *dest, const char *src);
is parsed like
Code: C  [Select][+][-]
  1. char (*strcpy)(char *dest, const char *src);
and returns one char, not c-style string?

These are not function pointers, but function declarations. You have a function pointer if you either have a typedef or declare a variable/field with a function header syntax. E.g.

Code: C  [Select][+][-]
  1. struct Whatever
  2. {
  3.   void (*someproc)();
  4. }

This is a struct with a pointer to void function as its only field.

Your function declaration from earlier is essentially parsed like this:

Code: C  [Select][+][-]
  1. char* strcpy(...);

A function pointer to a strcpy compatible function would look like this:

Code: C  [Select][+][-]
  1. typedef char* (*StrCpyFunc)(...);

I mean that the code without pointer
Code: C  [Select][+][-]
  1. typedef void my_annoying_c_function(size_t sz);
  2.  
  3. my_annoying_c_function func;
is absolutely legal.

Yes, but you can't do anything with it:

Code: C  [Select][+][-]
  1. int somefunc()
  2. {
  3.    return 42;
  4. }
  5.  
  6. typedef int IntFunc();
  7.  
  8. int main()
  9. {
  10.    IntFunc func1 = somefunc;
  11.    IntFunc func2 = &somefunc;
  12.    IntFunc func;
  13.    
  14.    func = somefunc;
  15.    func = &somefunc;
  16.  
  17.    return func();
  18. }

Code: [Select]
PS X:\> clang.exe func.c
func.c:10:12: error: illegal initializer (only variables can be initialized)
   IntFunc func1 = somefunc;
           ^
func.c:11:12: error: illegal initializer (only variables can be initialized)
   IntFunc func2 = &somefunc;
           ^
func.c:14:9: error: non-object type 'IntFunc' (aka 'int ()') is not assignable
   func = somefunc;
   ~~~~ ^
func.c:15:9: error: non-object type 'IntFunc' (aka 'int ()') is not assignable
   func = &somefunc;
   ~~~~ ^
4 errors generated.
Title: Re: How to translate typedef void * to Pascal?
Post by: Warfley on May 13, 2020, 02:10:00 pm
You mean void, not void*. The * in the example is simply the notation for function pointer. A function pointer to a function returning a void* would be void* *func().
No, because of the bracketing it is referring to void* ... not to void (*...
To quote the C 2011 standard (page 134): http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
Quote
EXAMPLE 1 The declaration
int f(void), *fip(), (*pfi)();
[...]
The binding  of *fip() is *(fip()), so that  the declaration  suggests,  and  the  same  construction  in  an  expression  requires,  the  calling  of  a  function fip, [...].  In  the  declarator (*pfi)(),  the extra parentheses are necessary to indicate that indirection through a pointer to a function yields a function designator [...]
Title: Re: How to translate typedef void * to Pascal?
Post by: tetrastes on May 13, 2020, 02:10:02 pm

These are not function pointers, but function declarations. You have a function pointer if you either have a typedef

You are wrong. See post of Warfley. If you need function pointer, you need explicitly use brackets, with or without typedef.

Quote
Your function declaration from earlier is essentially parsed like this:

Code: C  [Select][+][-]
  1. char* strcpy(...);

A function pointer to a strcpy compatible function would look like this:

Code: C  [Select][+][-]
  1. typedef char* (*StrCpyFunc)(...);

Yes, but typedef does not make from
Code: C  [Select][+][-]
  1. char* func(...);
neither
Code: C  [Select][+][-]
  1. char* (*func)(...);
nor
Code: C  [Select][+][-]
  1. char (*func)(...);
as you write in yor previous post.

Quote
I mean that the code without pointer
Code: C  [Select][+][-]
  1. typedef void my_annoying_c_function(size_t sz);
  2.  
  3. my_annoying_c_function func;
is absolutely legal.

Yes, but you can't do anything with it:

Yes, of cause,it is only another way to declare
Code: C  [Select][+][-]
  1. void func(size_t sz);
  2.  

And now change your code as you believe it will work:
Code: C  [Select][+][-]
  1. int somefunc()
  2. {
  3.    return 42;
  4. }
  5.  
  6. typedef int *IntFunc();   //  ADD * HERE
  7.  
  8. int main()
  9. {
  10.    IntFunc func1 = somefunc;
  11.    IntFunc func2 = &somefunc;
  12.    IntFunc func;
  13.    
  14.    func = somefunc;
  15.    func = &somefunc;
  16.  
  17.    return func();
  18. }

Code: Bash  [Select][+][-]
  1. $ gcc test.c
  2. test.c: In function 'main':
  3. test.c:10:4: error: function 'func1' is initialized like a variable
  4.    10 |    IntFunc func1 = somefunc;
  5.       |    ^~~~~~~
  6. test.c:11:4: error: function 'func2' is initialized like a variable
  7.    11 |    IntFunc func2 = &somefunc;
  8.       |    ^~~~~~~
  9. test.c:14:9: error: lvalue required as left operand of assignment
  10.    14 |    func = somefunc;
  11.       |         ^
  12. test.c:15:9: error: lvalue required as left operand of assignment
  13.    15 |    func = &somefunc;
  14.       |         ^
  15. test.c:17:11: warning: returning 'int *' from a function with return type 'int' makes integer from pointer without a cast [-Wint-conversion]
  16.    17 |    return func();
  17.       |           ^~~~~~
  18.  
  19.  
Title: Re: How to translate typedef void * to Pascal?
Post by: jiaxing2 on May 13, 2020, 06:17:55 pm
C sucks. I hate C  >:(
Title: Re: How to translate typedef void * to Pascal?
Post by: jamie on May 14, 2020, 01:56:09 am
na, C is just fine... I have no issues with it...

Your problem is you are getting confused from all this advice you are getting that is just talking you in all four directions..

 How to tell who's advice and who's theories you want to believe!

 :)
Title: Re: How to translate typedef void * to Pascal?
Post by: Warfley on May 14, 2020, 02:38:39 am
Well function pointers in C are simply pretty bad. I mean the best indicator how bad they are is that C++ introduced a new type (std::function) so you never have to use that awful C-syntax anymore.

There are only a few things where C++ decided to "replace" C features (of course C is still a subset of C++, but there are things you should not be using in C++ that are just there for C compatibility) like NULL-pointer, C-Strings or function pointers. Because C screwed that up really hard.

I mean simply the fact that there is so much confusion about such an essential language feature as function pointers shows that they are not simple
Title: Re: How to translate typedef void * to Pascal?
Post by: PascalDragon on May 14, 2020, 10:30:37 am

These are not function pointers, but function declarations. You have a function pointer if you either have a typedef

You are wrong. See post of Warfley. If you need function pointer, you need explicitly use brackets, with or without typedef.

Whatever.

The point I was trying to make is that the following does not have a direct representation in Pascal and isn't really useable without a pointer to it in C either:

Code: C  [Select][+][-]
  1. typedef int SomeFunc();

So in Pascal always a function or procedure variable needs to be used for this.
Title: Re: How to translate typedef void * to Pascal?
Post by: tetrastes on May 14, 2020, 02:00:50 pm

The point I was trying to make is that the following does not have a direct representation in Pascal and isn't really useable without a pointer to it in C either:

Code: C  [Select][+][-]
  1. typedef int SomeFunc();

So in Pascal always a function or procedure variable needs to be used for this.

So the code from the first question

Code: C  [Select][+][-]
  1. typedef void *my_annoying_c_function(size_t sz);

also does not have a direct representation in Pascal.
Title: Re: How to translate typedef void * to Pascal?
Post by: PascalDragon on May 15, 2020, 10:06:08 am

The point I was trying to make is that the following does not have a direct representation in Pascal and isn't really useable without a pointer to it in C either:

Code: C  [Select][+][-]
  1. typedef int SomeFunc();

So in Pascal always a function or procedure variable needs to be used for this.

So the code from the first question

Code: C  [Select][+][-]
  1. typedef void *my_annoying_c_function(size_t sz);

also does not have a direct representation in Pascal.

Yes, you're right. But as long as it is used as my_annoying_c_function *somevar translating it as a function pointer is legitimate.
Title: Re: How to translate typedef void * to Pascal?
Post by: BrunoK on May 15, 2020, 12:26:13 pm
Would that be relevant for typing and use ?
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. type
  4.   // typedef void my_annoying_c_function(size_t sz)
  5.   TMy_annoying_c_function = function(sz: size_t): {void} intptr;
  6.  
  7. function my_annoying_c_func(sz: size_t): intptr;
  8. begin
  9.   Result := sz;
  10. end;
  11.  
  12. const
  13.   my_annoying_c_function: TMy_annoying_c_function = @my_annoying_c_func;
  14.  
  15. begin
  16.   writeln(my_annoying_c_func(5));
  17.   readln;
  18. end.
  19.  
Edit :
Replace 
Code: [Select]
  writeln(my_annoying_c_func(5));with
Code: [Select]
  writeln(my_annoying_c_function(5));
Title: Re: How to translate typedef void * to Pascal?
Post by: tetrastes on May 15, 2020, 01:16:03 pm
Code: C  [Select][+][-]
  1. #include <stdio.h>
  2.  
  3. typedef long long (*Tmy_annoying_c_function)(size_t sz);
  4.  
  5. long long my_annoying_c_func(size_t sz)
  6. {
  7.   return sz;
  8. }
  9.  
  10. const
  11.   Tmy_annoying_c_function my_annoying_c_function = my_annoying_c_func;
  12.  
  13. void main(void)
  14. {
  15.   printf("%d\n", my_annoying_c_function(5));
  16.   scanf("%*c");
  17. }
  18.  
Title: Re: How to translate typedef void * to Pascal?
Post by: Warfley on May 15, 2020, 02:25:47 pm
[...]
Except "long long int" is not IntPtr, the corresponding c type would be intptr_t from stdint.h and printf does not replace WriteLn, which can be seen quite good here because your format string is broken (%d prints an int, to print long long int you need to use lld or lli. when you would be using intptr_t you would need to distinguish between 32 and 64 bit and use ld and lld respectively), which is not possible with WriteLn because there the compiler takes care of such things.

Not all Pascal programs have a perfect C representation, as pretty well seen by your example. The other direction is much better (i.e. C to pascal) because nearly all C constructs have a representation in pascal and you can use the libc in pascal (while you can't use the RTL in C).

That said, these are two different languages and not everything has a 1-1 translation and some problems are simply to be expected when trying to convert from one language to the other. But your chances are better when trying to convert C to Pascal than the other way around
Title: Re: How to translate typedef void * to Pascal?
Post by: tetrastes on May 15, 2020, 04:52:34 pm
On my system IntPtr and intptr_t are long long ;), though in general you are right. But in more general you are not right:
To quote the C 2011 standard (page 291) from your link: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
Quote
7.20.1.4 Integer types capable of holding object pointers
1 The following type designates a signed integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
intptr_t
The following type designates an unsigned integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
uintptr_t
These types are optional.
Note the last line. So you may not only not find intptr_t in stdint.h (for example at gcc it is defined in crtdefs.h), but not find it at all.

As for printf, you are right again in general, but in this specific example printf prints "5" and nothing else, and %d do it quite well, so you need not %lld here.

And of cause I agree that "Not all Pascal programs have a perfect C representation" and with all other clever words.
TinyPortal © 2005-2018