【C言語】
うるう年を判定する複数の方法
(関数版,論理式版,マクロ版,inline関数版)

warning: suggest parentheses around ‘&&’ within ‘||’

警告:X&&Y||Zは(X&&Y)||Zと丸括弧を付けて
[-Wparentheses]


この記事の概要

この記事は、C言語でうるう年を判定する複数の方法(関数版、論理式版、マクロ版、inline関数版)を解説し、それぞれの利点や非推奨ポイントを紹介します。また、コンパイラ(GCCやClang)からの警告「&& と || の組み合わせに丸括弧を付ける」推奨理由やその解決策も詳述します。最も効率的なプログラムのスタイルと警告対策を知りたい方におすすめの内容です。

■うるう年判定プログラム-関数版

#include <stdio.h>
int isleap(int year)   {
    if (year % 4 == 0) {
        if (year % 100 == 0) {
            if (year % 400 == 0) {
                return 1;//"閏年です";
            } else {
                return 0;//"閏年ではありません";
            }
        } else {
            return 1;//"閏年です";
        }
    } else {
        return 0;//"閏年ではありません";
    }
}
int main(void){
    for(int year = 1582 ; year <= 2038 ;year++){
        if(isleap(year)){
            printf("%d年は閏年です\n",year);
        } else {
            printf("%d年は閏年ではありません\n",year);
        }
    }
}

記述量が多いので非推奨です。


■うるう年判定プログラム-論理式版

#include <stdio.h>
int main(void){
    for(int year = 1582 ; year <= 2038 ;year++){
        if((year%4==0 && year%100!=0) || year%400==0){
            printf("%d年は閏年です\n",year);
        } else {
            printf("%d年は閏年ではありません\n",year);
        }
    }
}

論理式一行if文中に書いたので
行が長くなります。


■うるう年判定プログラム-マクロ版

#include <stdio.h>
#define isleap(Y) (\
    ((Y)%4==0 && (Y)%100!=0) || (Y)%400==0\
)
int main(void){
    for(int year = 1582 ; year <= 2038 ;year++){
        if(isleap(year)){
            printf("%d年は閏年です\n",year);
        } else {
            printf("%d年は閏年ではありません\n",year);
        }
    }
}

丸括弧がうるさいのであまり推奨しません。


■うるう年判定プログラム-inline関数版

#include <stdio.h>
static inline int isleap(int y) {
    return  (y%4==0 && y%100!=0) || y%400==0 ;
}
int main(void){
    for(int year = 1582 ; year <= 2038 ;year++){
        if(isleap(year)){
            printf("%d年は閏年です\n",year);
        } else {
            printf("%d年は閏年ではありません\n",year);
        }
    }
}

このスタイルを一番推奨します。


■gccの警告

聖典プログラミング言語Cで閏年判定は
leap = year%4==0 && year%100!=0 || year%400==0と紹介されています。

でもこのスタイルは
gccやclangに丸括弧を付けてと警告されます。

ちょっと簡略化けして
leap = (x&&Y)||Z;と
leap = X&&(Y||Z);は、
どちらが正しいでしょうか?

この閏年判定の論理式の場合
どちらも正しいとWikipedia
説明されています。

丸括弧の位置で動作が変わる論理式もあるので
丸括弧を付けるようにしましょう。


参考:

C-FAQ 20.32

isleap