warning: the frame size of 40 bytes is larger than 0 bytes
警告:スタックフレームサイズは0byte以上の40byte
[-Wframe-larger-than=0]
■1.int型より狭いcharやshortを使うと
メモリサイズが増える!?
メモリの1byteは血の一滴と言われた時代の影響か
令和の時代の今でもメモリ節約と称して
int型より狭い型(char/short型)を
多用する古い習慣がまだあります。
昔のANSI-C非準拠の組み込みマイコン用コンパイラでは狭い型(char/short型)を多用するとメモリ節約になったようですが
現代のコンパイラではどうでしょうか?
実験してみましょう。
■2.比較実験用ソースコード
#include <stdio.h>
typedef unsigned char U1 ;
typedef unsigned int U4 ;
void MYmemset(void *p,int x,size_t size)
{
U1 *buf = p ;
for(TYPE i = 0;i < size;i++){
buf[i] = x;
}
}
int main(void)
{
char buf[1024];
MYmemset(buf,0xFF,sizeof(buf));
printf("%c%c\n",buf[0],buf[1023]);
}
■3.比較実験用SHELLスクリプト
#スタックサイズを調べる(最適化無し)
gcc MYmemset.c -DTYPE=U1 -c -Wframe-larger-than=0
gcc MYmemset.c -DTYPE=U4 -c -Wframe-larger-than=0
#スタックサイズを調べる(最適化有り)
gcc MYmemset.c -DTYPE=U1 -c -Wframe-larger-than=0 -O
gcc MYmemset.c -DTYPE=U4 -c -Wframe-larger-than=0 -O
#TEXT/DATA/BSSサイズを調べる
gcc MYmemset.c -DTYPE=U1 -c -O
size MYmemset.o
gcc MYmemset.c -DTYPE=U4 -c -O
size MYmemset.o
exit
実験用SHELLスクリプト
(1) gcc -Wframe-larger-than=0 でスタックサイズを調べる
(2) size コマンドで TEXT/DATA/BSSのサイズを調べる
■4.実験結果:U4型よりU1型のほうがサイズが増えた
+ gcc MYmemset.c -DTYPE=U1 -c -Wframe-larger-than=0
MYmemset.c: In function ‘MYmemset’:
MYmemset.c:10:1: warning: the frame size of 40 bytes is larger than 0 bytes [-Wframe-larger-than=]
10 | }
| ^
MYmemset.c: In function ‘main’:
MYmemset.c:16:1: warning: the frame size of 1040 bytes is larger than 0 bytes [-Wframe-larger-than=]
16 | }
| ^
+ gcc MYmemset.c -DTYPE=U4 -c -Wframe-larger-than=0
MYmemset.c: In function ‘MYmemset’:
MYmemset.c:10:1: warning: the frame size of 40 bytes is larger than 0 bytes [-Wframe-larger-than=]
10 | }
| ^
MYmemset.c: In function ‘main’:
MYmemset.c:16:1: warning: the frame size of 1040 bytes is larger than 0 bytes [-Wframe-larger-than=]
16 | }
| ^
+ gcc MYmemset.c -DTYPE=U1 -c -Wframe-larger-than=0 -O
MYmemset.c: In function ‘main’:
MYmemset.c:16:1: warning: the frame size of 1040 bytes is larger than 0 bytes [-Wframe-larger-than=]
16 | }
| ^
+ gcc MYmemset.c -DTYPE=U4 -c -Wframe-larger-than=0 -O
MYmemset.c: In function ‘main’:
MYmemset.c:16:1: warning: the frame size of 1040 bytes is larger than 0 bytes [-Wframe-larger-than=]
16 | }
| ^
+ gcc MYmemset.c -DTYPE=U1 -c -O
+ size MYmemset.o
text data bss dec hex filename
224 0 0 224 e0 MYmemset.o
+ gcc MYmemset.c -DTYPE=U4 -c -O
+ size MYmemset.o
text data bss dec hex filename
223 0 0 223 df MYmemset.o
+ exit
(1)ループカウンタがU1型の時もU4型の時も
共にスタックサイズは40byte。
※-Oで最適化するとスタックサイズは共に0になりました
(レジスタに割り付けられた模様)
(2)textサイズ(=ROMサイズ)は
U1型の時224byte
U4型の時223byte
■5.注意事項
(1) スタックサイズは
コンパイラの種類や最適化の有無で変わります。
(2) このプログラムは
TYPEがU1型の時無限ループします。
U1型では1024を表現できず無限ループしますが、
gcc/clangの警告では検出できません。
(3) 一般的に狭い型の演算ではint型への型変換が発生するため
この分ROMサイズが増加し処理速度も劣化します。
参考:
C-FAQ 1.1: 予想不能な符号拡張の問題とコード サイズの増加
http://www.kouno.jp/home/c_faq/c1.html#1
int よりも狭いビット幅の型の多用を避ける。
https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c907.html