1. ホーム
  2. c

[解決済み] ループや条件文なしで1から1000まで表示するC言語のコードはどのように動作するのでしょうか?

2022-05-10 10:34:40

質問

私は C というコードで はループや条件なしで 1 から 1000 までを表示します。 : しかし、私はそれがどのように動作するかを理解していない。誰かコードを見て、各行を説明することができますか?

#include <stdio.h>
#include <stdlib.h>

void main(int j) {
  printf("%d\n", j);
  (&main + (&exit - &main)*(j/1000))(j+1);
}

どのように解決するのですか?

こんなコードは書かないようにしましょう。


のために j<1000 , j/1000 はゼロ(整数除算)です。だから

(&main + (&exit - &main)*(j/1000))(j+1);

とは等価である。

(&main + (&exit - &main)*0)(j+1);

というのは。

(&main)(j+1);

どの呼び出し mainj+1 .

もし j == 1000 であれば、同じ行が次のように出てきます。

(&main + (&exit - &main)*1)(j+1);

ということになります。

(&exit)(j+1);

どれが exit(j+1) と表示され、プログラムを終了します。


(&exit)(j+1) そして exit(j+1) は本質的に同じものです - C99 §6.3.2.1/4 を引用しています。

関数指示子は、関数型を持つ式である。ただし、それが のオペランドが や単項の & 演算子 を持つ関数指示子である場合は 型である。 型を返す関数 は、型 " を持つ式に変換されます。 へのポインタ を返す関数 という型に変換されます。

exit は関数指定子です。単項演算子がなくても & address-of演算子がなくても、関数へのポインタとして扱われます。(その際 & はそれを明示するだけです)。

また、関数呼び出しは§6.5.2.2/1以降に記述されています。

呼び出される関数を表す式は、型が 関数へのポインタ voidを返すか、配列型以外のオブジェクト型を返す。

そのため exit(j+1) は関数型から関数へのポインタ型に自動的に変換されるため動作します。 (&exit)(j+1) はポインタから関数への型への明示的な変換で同様に動作します。

とはいえ、上記のコードは適合していません( main は二つの引数を取るか、全く取らないかのどちらかです)、そして &exit - &main は§6.5.6/9によると未定義であると思います。

2つのポインタが引き算されるとき は両方とも同じ配列オブジェクトの要素を指すものとします。 または配列オブジェクトの最後の要素より1つ後を指すこと; ...

追加された (&main + ...) はそれ自体が有効であり、使用することができるだろう。 もし は、§6.5.6/7にあるように、加えられた量がゼロであった場合、使用することができます。

これらの演算子の目的のために、配列の要素でないオブジェクトへのポインタは、長さ1の配列の最初の要素へのポインタと同じように動作します。 配列の要素でないオブジェクトへのポインタは、長さ1の配列の最初の要素へのポインタと同じように動作し、その要素の型はオブジェクトの型となります。 を要素型とする長さ1の配列の最初の要素へのポインタと同じように動作します。

ですから、ゼロを追加して &main は大丈夫でしょう(でもあまり意味がない)。