【C言語】
配列の添字の型は何が良い?

warning: the frame size of 40 bytes is larger than 0 bytes

警告:スタックフレームサイズは0byte以上の40byte
[-Wframe-larger-than=0]


■int型より狭いcharやshortを使うと
メモリサイズが増える!?

メモリの1byteは血の一滴と言われた時代の影響か
令和の時代の今でもメモリ節約と称して
int型より狭い型(char/short型)を
多用する古い習慣がまだあります。

昔のANSI-C非準拠の組み込みマイコン用コンパイラでは狭い型(char/short型)を多用するとメモリ節約になったようですが
現代のコンパイラではどうでしょうか?
実験してみましょう。


■比較実験用ソースコード

#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]);
}

■比較実験用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のサイズを調べる



■実験結果: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

■注意事項

(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