# Passing optional Fortran arguments to C

**URL:** <https://fortran-lang.discourse.group/t/passing-optional-fortran-arguments-to-c/4223>\
**Category:** Help\
**Created:** [August 25, 2022, 6:57pm UTC](https://fortran-lang.discourse.group/t/passing-optional-fortran-arguments-to-c/4223 "2022-08-25T18:57:56Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![gnikit](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/gnikit/32/1213_2.png) [@gnikit](https://fortran-lang.discourse.group/u/gnikit)\
**Post date:** [August 25, 2022, 6:57pm UTC](https://fortran-lang.discourse.group/t/passing-optional-fortran-arguments-to-c/4223/1 "2022-08-25T18:57:56Z")

</div>

I am in the process of writing a Fortran API to a C header for a library and I have run into some issues when it comes to implementing `optional` arguments. Specifically, the Fortran API works by calling on a C API, which allows for optional arguments by passing `NULL` as the value\[1\]. I am curious as to what is a **standard compliant** way of passing Fortran optional arguments to C. These arguments can be variables, strings, arrays, arrays of strings, etc. **but not Fortran pointers**. Is it enough to mark them as `optional` in the Fortran method and the C `interface` block? Can we use the Fortran “presentness”, or lack thereof to indicate `NULL` in C?

I asked this question on Stack Overflow but I have gotten mixed answers, especially whether the code is standard conformant. (Probably I could have done a better job structuring the question.)

## Specific Questions

1. Do I need to add `optional` in both the Fortran procedure and the C `interface` binding block?
2. Can we use the Fortran `present` in a procedure, or lack thereof to indicate `NULL` in C?
3. Is passing `array_size=size(array, kind=c_size_t)` considered standard conforming when `array` itself might not be present? (Assuming that there is some safety check mechanism for `array` being `NULL` on the C side).  
3.1. We can’t mark `array_size` as `optional` because it uses the `value` attribute (and we can’t change the C code). An alternative would be to set the `array_size=local_size` to some local variable which is set to `0` if the `array` is not present, but in that case what would be the input value of `array` when not present?

> **Minimal Working Example**
>
> ```fortran
> program main
> use, intrinsic :: iso_c_binding
> implicit none
> call null_str_f90("abc"); call null_str_f90()
> call null_array_opt_f90([1, 2, 3, 4, 5]); call null_array_opt_f90()
> 
> contains
> 
> function istring_(o) result(v)
> character(len=*), intent(in) :: o
> character(len=:, kind=c_char), allocatable :: v
> v = trim(o)//c_null_char
> end function istring_
> 
> subroutine null_str_f90(str)
> interface
> subroutine C_API(str_c) bind(C, name="null_str")
> use, intrinsic :: iso_c_binding
> character(len=1, kind=c_char), dimension(*), optional, intent(in) :: str_c ! is the optional keyword here necessary?
> end subroutine C_API
> end interface
> character(len=*), intent(in), optional :: str
> ! Local variables
> character(len=:, kind=c_char), allocatable :: name_c
> if (present(str)) name_c = istring_(str)
> call C_API(str_c=name_c) ! is this standard compliant?
> end subroutine null_str_f90
> 
> subroutine null_array_opt_f90(array)
> interface
> subroutine C_API(array, array_size) bind(C, name="null_array")
> use, intrinsic :: iso_c_binding
> integer(c_int), dimension(*), optional :: array
> integer(c_size_t), value, intent(in) :: array_size
> end subroutine C_API
> end interface
> integer(c_int), dimension(:), optional, intent(in) :: array
> ! Is this call even legal? array_size is passed by VALUE but array is not PRESENT
> call C_API(array=array, array_size=size(array, kind=c_size_t))
> end subroutine null_array_opt_f90
> 
> end program main
> 
> ```
> 
> ```c
> #include <stdio.h>
> 
> void null_str(const char *str) {
> if (str) {
> printf("str is present: str is %s\n", str);
> } else {
> printf("str is not present\n");
> }
> }
> 
> void null_array(int *array, size_t size) {
> if (array) {
> for (int i = 0; i < size; i++) printf("%d ", array[i]);
> printf("\n");
> } else {
> printf("array is not present\n");
> }
> }
> 
> ```

For me the MWE posted above produces the expected results, but I am not convinced my approach is correct or portable across compilers.

* * *

1. Whether or not that is a good idea is a completely separate matter, but long story short I don’t have any control over the C code.

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [August 25, 2022, 11:11pm UTC](https://fortran-lang.discourse.group/t/passing-optional-fortran-arguments-to-c/4223/2 "2022-08-25T23:11:10Z")

</div>

> [@gnikit](#):
>
> … We can’t mark `array_size` as `optional` because it uses the `value` attribute (and we can’t change the C code). An alternative would be to set the `array_size=local_size` to some local variable which is set to `0` if the `array` is not present, but in that case what would be the input value of `array` when not present? …

Everything looks alright with the example shown except for the part relevant to the quoted comment above.

It is nonconforming in Fortran to reference an absent argument as the first argument (`ARRAY`) in the `SIZE` intrinsic.

So you will have to modify the MWE, specifically the `null_array_opt` procedure and in it, check whether `array` is present and act accordingly:

```fortran
   if ( present( array ) ) then
      call C_API( array=array, array_size=size(array, kind=c_size_t) )
   else
      call C_API( array_size=0_c_size_t )
   end if

```

---

<div class="post-metadata">

**Author:** ![gnikit](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/gnikit/32/1213_2.png) [@gnikit](https://fortran-lang.discourse.group/u/gnikit)\
**Post date:** [August 25, 2022, 11:25pm UTC](https://fortran-lang.discourse.group/t/passing-optional-fortran-arguments-to-c/4223/3 "2022-08-25T23:25:23Z")

</div>

I suspected as such (about the `size(array, kind=c_size_t)`). Is doing the following equally valid to your proposed solution?

```fortran
integer(c_size_t) :: lsize
lsize = 0
if (present(array)) lsize = size(array, kind=c_size_t)
call C_API(array=array, array_size=lsize)

```

I am trying to keep the `C_API` call as simple as possible, especially since the procedures can have multiple arguments which are all optional, so the if-else conditionals would become quite complicated. The entire Fortran API is autogenerated based on a bunch of rules and a Python script

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [August 25, 2022, 11:30pm UTC](https://fortran-lang.discourse.group/t/passing-optional-fortran-arguments-to-c/4223/4 "2022-08-25T23:30:07Z")

</div>

> [@gnikit](#):
>
> … Is doing the following equally valid to your proposed solution? …

Yes, that’s fine.

In the Fortran code, it is somewhat a matter of style as to whether to have code that is equivalent to what a processor might do “under the hood” as with your proposed solution, or with the `if-conditionals` that is the pedantic way of showing how to work with the optional parameters.

If the former style works better with autogenerated code, then so be it.

---

<div class="post-metadata">

**Author:** ![gnikit](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/gnikit/32/1213_2.png) [@gnikit](https://fortran-lang.discourse.group/u/gnikit)\
**Post date:** [August 25, 2022, 11:36pm UTC](https://fortran-lang.discourse.group/t/passing-optional-fortran-arguments-to-c/4223/5 "2022-08-25T23:36:49Z")

</div>

Thanks a lot for the help!

I am now wondering if the behaviour from gfortran, compiling and running successfully  
`C_API( array=array, array_size=size(array, kind=c_size_t) )` when `array` is `.not. present`, is intentional and if it’s not why it’s not breaking at runtime.

I suspect there is a good reason either way.

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [August 25, 2022, 11:59pm UTC](https://fortran-lang.discourse.group/t/passing-optional-fortran-arguments-to-c/4223/6 "2022-08-25T23:59:36Z")

</div>

There is no numbered constraint against the nonconformant use of an unallocated allocatable variable or a pointer that is not associated (which is what an absent argument can be considered to be) as the `ARRAY` argument in the `SIZE` intrinsic. The onus lies on the program author to conform. The processor cannot be relied upon here.
