こんなかたちで終わることしかできない私を許して下さい

今 万感の思いを込めて 命令が実行される
今 万感の思いを込めて PC(プログラムカウンタ)が進む
ひとつのプログラムは終わり また新しいプログラムが始まる
さらばAVR
さらばmain関数
さらば少年の日よ
(十分な間を置く)
(GODIGOのあの曲が流れる)

一般的にmain()関数は
int main(void)
もしくは
int main(int argc, char **argv)
と書きます。
しかし、仕様上はOSのサポートが無い環境(フリースタンディング環境)では
void main(void)
などの処理系独自の表記も許されています。

ではAVRのプログラムでint main(void)とvoid main(void)で何か違いがあるでしょうか?さらにはmain関数の最後のreturn文での返り値に何か意味があるのでしょうか?

とりあえず、3つのパターンを試してしました。
パターン1 int main(void)形式でreturn 0
パターン2 int main(void)形式でreturn1
パターン3 void main(void)形式

それぞれのパターンのソースコードをmain1.c, main2.c, main3.cとして挙げます。

[c]
/* main1.c */
int main(void)
{
return 0;
}
[/c]

[c]
/* main2.c */
int main(void)
{
return 1;
}
[/c]

[c]
/* main3.c */
void main(void)
{
return;
}
[/c]

それぞれのコードをavr-gcc -S -mmcu=atmega328p main*.c でアセンブルしました。

結果は次のようになりました。
[plain]
.file "main1.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__CCP__ = 0x34
__tmp_reg__ = 0
__zero_reg__ = 1
.text
.global main
.type main, @function
main:
push r29
push r28
in r28,__SP_L__
in r29,__SP_H__
/* prologue: function */
/* frame size = 0 */
ldi r24,lo8(0)
ldi r25,hi8(0)
/* epilogue start */
pop r28
pop r29
ret
.size main, .-main
[/plain]

[plain]
.file "main2.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__CCP__ = 0x34
__tmp_reg__ = 0
__zero_reg__ = 1
.text
.global main
.type main, @function
main:
push r29
push r28
in r28,__SP_L__
in r29,__SP_H__
/* prologue: function */
/* frame size = 0 */
ldi r24,lo8(1)
ldi r25,hi8(1)
/* epilogue start */
pop r28
pop r29
ret
.size main, .-main
[/plain]

[plain]
.file "main3.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__CCP__ = 0x34
__tmp_reg__ = 0
__zero_reg__ = 1
.text
.global main
.type main, @function
main:
push r29
push r28
in r28,__SP_L__
in r29,__SP_H__
/* prologue: function */
/* frame size = 0 */
/* epilogue start */
pop r28
pop r29
ret
.size main, .-main
[/plain]

この結果を見る限りでは、int main(void)形式の場合はmain関数の返り値はmain関数の呼び出し元にしっかり返っています。void main(void)形式の場合は不定値が返っています。

「どうせmain関数の戻り値なんて使わない」という考えの下ではvoid main(void)形式がメモリ使用量が少なくベストです。しかし、main関数の戻り値についての警告(main3.c:2: warning: return type of ‘main’ is not ‘int’)が出ます。

さて、どのコードも最後にret命令があります。このret命令でmain関数から抜けていますがどこに処理が移るのでしょうか?
そろそろ、記事が長くなってきたので続きは次回に。

by Shiozaki

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です