The prototypes of standard interface functions  are specified in the POSIX standard.  It would be a POSIX violation to use whatever prototype you happen to like most.  No one gets to "improve" POSIX.

read() is specified here https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html and must *not* include const in the prototype.

On 7/13/2024 9:00 PM, Nathan Hartman wrote:
Replying inline below...

On Sat, Jul 13, 2024 at 3:21 PM Petro Karashchenko <
petro.karashche...@gmail.com> wrote:

Hi,

This comes more to the edge of coding language paradigms, personal
preferences and readability.
For enable in Rust everything that you define is "const" and if you want to
modify it you should explicitly specify it. On another hand in C everything
you define is modifiable unless you specify "const" to restrict unintended
modification at compile time. This is one of many items that you can find
in discussions why Rust is safer than the C.

The usage of "const" kind of improves compile time checking, but it adds
more text to the lines and makes code harder to read. Like when I looked
into https://github.com/apache/nuttx/pull/12683 I would maybe remove most
of the "const" there in cases like "const mfs_t depth" or "const struct
mfs_ctz_s new_ctz". But again this comes to personal preferences.

Personally I'm trying to balance on the edge and inspire from POSIX
sometimes. Of course POSIX could define "read" as "ssize_t read(const int
fildes, void * const buf, const size_t nbyte);", but it is defined as
"ssize_t
read(int fildes, void *buf, size_t nbyte);" that seems to be more readable
while still sacrifice compile time checking.


As I'm thinking more about this, I think it makes sense to define read as
ssize_t read(int fildes, void * buf, size_t nbyte) and NOT ssize_t
read(const int fildes, void * const buf, const size_t nbyte) because of the
following reason: specifying const in those places affects what the
function implementation can do internally with its stacked copies of those
values and address. So if you put those const in the function signature,
you would leak an internal implementation detail and you also would prevent
alternative implementations that might need to alter those values for the
function's use.

The only time I would suggest to put those 'const' is when the function is
static and part of a module's internal implementation, and is NOT exported
to the outside world in the form of an API that has to be maintained
forever.

More below...


This also becomes tricky when "const" may be used "when convenient" like in
"jrnl_rdlog" from https://github.com/apache/nuttx/pull/12683. The
"idx"/"pg" parameters of "jrnl_rdlog" seems also to need "const" like
"const mfs_t depth" from "jrnl_wrlog", but just because author had a
preference not to create a temporary variables "mfs_t tmp_pg = pg;"/"mfs_t
tmp_idx = idx;" and it was "more convenient" to use "idx"/"pg" then const
is omitted in that interface.

So summarizing, there is no answer of what is the best or what should be
used.

Note: "const" before or after "*" are ANSI-C compatible, so has nothing to
do with C++ feature enabled in C. Maybe there was something in between
K&R-C and ANSI-C, but that really goes too far back in time.


Thinking about how parsing of declarations works in C, it makes sense that
const before and after * should have been supported in those early C,
though I don't remember it being explicitly documented in K&R's C book. (I
originally learned C from K&R's The C Programming Language book and I never
heard of const after * until I learned C++.)

Cheers
Nathan

Reply via email to