分からないことを ChatGPT に尋ねて、なるほどーと思ったら、実は間違いだった (正しいことを教えてくれなかった)。 でも、自分の理解は進んだ、という話。
| call writec('Hello') | 
| void writec(char *buf, int len) | 
| nantoka.f | 
| 
       call writec('Hello')
       stop
       end
 | 
| kantoka.c | 
| 
#include <stdio.h>
void writec_(char *buf, int len)
{
   printf("%s, len=%d\n", buf, len);
}
 | 
| % gfortran nantoka.f kantoka.c % ./a.out Hello, len=5 % | 
本当だ。ところが
| nantoka2.f | 
| 
       call writec('Hello',5)
       stop
       end
 | 
| % gfortran nantoka2.f kantoka.c % ./a.out Hello, len=35946216 % | 
| kantoka2.c | 
| 
#include <stdio.h>
void writec_(char *buf, int *len)
{
   printf("%s, len=%d\n", buf, *len);
}
 | 
| % gfortran nantoka2.f kantoka2.c % ./a.out Hello, len=5 | 
なんじゃ、こりゃあ?? (昭和の人はお分かりになるかと思います。)
この辺で ChatGPT にお尋ねする。
まず文字列をCに渡すならば、NULL 終端にしましょう、と言われる。 それはそうだ (今やろうと思っていたのに)。
| 
       call writec('Hello' // char(0))
       stop
       end
       call writec('Hello' // char(0), 5)
       stop
       end
 | 
| ✅ 「文字列の長さは暗黙には渡されない可能性が高い」と言った理由 これは まさに処理系依存(=コンパイラ依存)です! 
🎯 つまり:
 それに対して Fortran が暗黙に長さ引数を追加するかどうかは、 引数の順番(最後かどうか)や、 他の引数の型や数(実数が続いている、明示の長さがある)などに依存し、 コンパイラの実装によって異なる可能性があります   
✅ よって、実用上の原則
 これが一番安全でポータブルな方針です。 
🛡 まとめ
 そのため、リテラルには // char(0) を付けて NULL 終端するのが安全。 あるいは character*X の変数にして長さを Fortran → C に明示的に渡すのも手。 ポータビリティや予測可能性を高めるためには、暗黙に頼らず明示で書くのが鉄則です。 | 
そうなんだ。すごい先生だ。
| いや〜ここまで突っ込んで理解されているのはすごいです。 デバッグもかなり深いところまで行ってる感じですね。 また疑問が出たら、いつでもどうぞ! | 
あれ?順番が最後にまとめてというだけで、長さは必ず渡してくれているようだよ。 最後にまとめて渡してくれるんだ。
| calling_c.f | 
|       character*10 s
      integer n
      character*5 s2
      s='HELLO' // char(0)
      n=3
      s2='bye' // char(0)
      call cfunc(s, n, s2)
      call cfunc('world' // char(0), 4, 'happy' // char(0))
      stop
      end
       | 
| cfunc.c | 
| #include <stdio.h>
#include <string.h>
void cfunc_(char *s, int *n, char *s2, int len_s, int len_s2)
{
  printf("s=%p, *s=%s, length(*s)=%d, n=%p, *n=%d, s2=%p, *s2=%s, length(*s2)=%d, len_s=%d, len_s2=%d\n",
	 s, s, strlen(s), n, *n, s2, s2, strlen(s2), len_s, len_s2);
}
 | 
引数として、文字列と、整数と、文字列を並べる。 文字列1へのポインター、整数へのポインター、文字列2へのポインター、 文字列1の長さ、文字列2の長さ、の順に渡される。
| % gfortran calling_c.f cfunc.c % ./a.out s=0x7ff7b70483d2, *s=HELLO, length(*s)=5, n=0x7ff7b70483dc, *n=3, s2=0x7ff7b70483cd, *s2=bye, length(*s2)=3, len_s=10, len_s2=5 s=0x108ebae86, *s=world, length(*s)=5, n=0x108ebaef0, *n=4, s2=0x108ebae80, *s2=happy, length(*s2)=5, len_s=6, len_s2=6 % | 
この実行結果を見ると、色々分かる。(昔、 まだ Fortran プログラムを読んだり書いたりしていた頃、 調べたのだけれど文字列周りは良く分からず、放置したままで来たけれど、 今回はまあまあの理解ができた。)
(なぜ ChatGPT は間違えたのか。誰か勘違いしている人が書いたものを読んだからかしら。 正しいかどうか、ちゃんとチェックしないとダメなんだけど、 そういうのは出来ないのかな。)