Does not alter what?
Does not alter the way the parameter is passed. That's what "const" does not alter (true in FPC, not in Delphi.)
When compiling your external function declaration, the compiler has no way of knowing what the original function expects.
That's correct. It relies entirely on the external function declaration. That's why the declaration is required.
If the compiler could take look into original function, we would not need to write external declarations at all.
Correct but, that doesn't have anything to do with the use of "const".
When you put const, you are telling the compiler to use whatever. And then the compiler will have to guess wheter to pass by value or by reference, and it's decision has fifty percent to be what the original function expects.
No. That is incorrect. When specifying "const", the compiler is being told that the value of the parameter cannot be changed by the function/procedure, that's all it does. Nothing else.
The programmer should instruct the compiler what to use - by using var or constref if "by reference" is expected, or nothing if "by value" is expected.
Correct but, in addition to that, in the case of "nothing or by value", the modifier "const" can be added to inform the compiler that the parameter cannot be assigned to.
You just had luck with your test. You might not with next fpc version. Or with another function with the same compiler version.
There was no luck involved at all. You could change the declaration, which in the example I attached is currently
function WriteFile(FileHandle : THANDLE;
const Buffer : pointer;
NumberOfBytesToWrite : DWORD;
var NumberOfBytesWritten : DWORD;
Overlapped : POverlapped)
: BOOL; stdcall; external 'kernel32';
to:
function WriteFile(const FileHandle : THANDLE;
const Buffer : pointer;
const NumberOfBytesToWrite : DWORD;
var NumberOfBytesWritten : DWORD; // DON'T change "var" to "const", that would make the definition incorrect.
const Overlapped : POverlapped)
: BOOL; stdcall; external 'kernel32';
and the code generated would be
identical and the API call would work fine because "const" does not alter the way the parameter is passed.
Just to save you the hassle, I did it and, here is the result (feel free to change the declaration to match the one above and run the code to convince yourself.)
SortCount.lpr:328 Ok := WriteFile(FileHandle,
00401967 6a00 push $0x0
00401969 8d45e4 lea -0x1c(%ebp),%eax
0040196C 50 push %eax
0040196D ff75ec pushl -0x14(%ebp)
00401970 ff75f8 pushl -0x8(%ebp)
00401973 ff75f0 pushl -0x10(%ebp)
00401976 e885f6ffff call 0x401000 <_$dll$kernel32$WriteFile>
0040197B 8945e8 mov %eax,-0x18(%ebp)
SortCount.lpr:334 if not Ok then Error(3);
0040197E 85c0 test %eax,%eax
You can compare with the code in my previous post and, you'll see it is identical.
Maybe a CONSTREF for any exported functions should be forced when doing LIB code?
For any external declaration, the presence of "const" is superfluous because it can only be used for parameters passed by value and, the compiler has no way to prevent the external function from locally altering their values.
Whenever you see var, in an external declaration, you could change it to "constref" and it would make no difference, because what really matters is the "ref" part, which informs the compiler the parameter is being passed by reference. In the case of an external declaration, the compiler has no way of enforcing the "const" part.
For instance, the WriteFile API definition could be
function WriteFile(const FileHandle : THANDLE;
const Buffer : pointer;
const NumberOfBytesToWrite : DWORD;
constref NumberOfBytesWritten : DWORD;
const Overlapped : POverlapped)
: BOOL; stdcall; external 'kernel32';
and it would work just fine too, even though specifying "constref" for the NumberOfBytesWritten is a lie since its value is changed by the API call.
That said, even though specifying NumberOfBytesWritten as constref is a bit of a lie, doing so could prevent a programmer inadvertently overwriting the value returned by the API call in the remainder of the function containing the call, which would most likely be a programming mistake.
The important part is the "ref" which causes the parameter to be passed by reference just as "var" does.
ETA:NOTE: declaring parameters as "const" which are not really constant will work fine in 32bit but will likely cause problems in 64bit.