gcc で 64bit と 32bit のコードを使い分けるために便利なマクロ


動機

卒論のための開発の中で、64bit と 32bit の両方で実験する必要があり、コードを使い分けたい、と思い調べました。
めっちゃ忘れそうなので備忘録として残しておきます。
なお、テスト環境以外でも同じマクロの定義になっているかは確認できていないことをご留意ください。

テスト環境

  • Ubuntu 16.04.6 LTS
  • gcc 5.4.0

プリプロセッサが定義するマクロの確認方法

gcc では、プリプロセッサが定義してくれるマクロがいろいろあります。
それらは、以下のコマンドで確認可能です。
参考: gcc のプリプロセッサの定義済みマクロ(Predefined Macros)の確認方法

echo | cc -dM -E -

64bit 環境で 32bit 用にコンパイルする方法

-m32 をつけてコンパイルすることで、32bit 用のコードを生成することができます。
参考: 64bit Linuxで32bit ELFをコンパイル

gcc -m32 hello.c

32bit のときに定義されるマクロの確認方法

32bit 用にコンパイルしたときには、 __code_model_m32__ というマクロが定義されます。
先ほどのプリプロセッサのマクロの表示を、32bit と 64bit の両方で行って、diffを取ってそれっぽいものを探すと出てきました。
筆者の環境と違う場合でも、同じ方法で調べられそうですね。

$ diff <(echo | gcc -dM -E -m32 - | grep 32) <(echo | gcc -dM -E - | grep 32)
9c9
< #define __INT_FAST32_MAX__ 0x7fffffff
---
> #define __INT_FAST32_MAX__ 0x7fffffffffffffffL
14,15c14
< #define __code_model_32__ 1
< #define __INT_FAST32_TYPE__ int
---
> #define __INT_FAST32_TYPE__ long int
17c16
< #define __UINT_FAST32_MAX__ 0xffffffffU
---
> #define __UINT_FAST32_MAX__ 0xffffffffffffffffUL
19a19
> #define __ORDER_BIG_ENDIAN__ 4321
24d23
< #define __ORDER_BIG_ENDIAN__ 4321
27c26
< #define __UINT_FAST32_TYPE__ unsigned int
---
> #define __UINT_FAST32_TYPE__ long unsigned int

実際にマクロを使ってみた

#include <stdio.h>

int main() {
#ifdef __code_model_32__
  printf("32bit ");
  printf("sizeof(void *): %d\n", sizeof(void *));
#else
  printf("64bit ");
  printf("sizeof(void *): %ld\n", sizeof(void *));
#endif
  return 0;
}
$ gcc -m32 test.c
32bit sizeof(void *): 4
$ gcc test.c
64bit sizeof(void *): 8

以上になります。
誤り等があればご指摘いただけると幸いです。

もっと便利な方法があるらしい

@ SaitoAtsushi さん、ご指摘ありがとうございます

この記事の例の場合であれば sizeof の返却値の型である size_t の大きさによって分岐したいはずなので stdint.h にある SIZE_MAX を使うのが手頃かと思います。