warning: suggest parentheses around ‘&&’ within ‘||’
警告:X&&Y||Zは(X&&Y)||Zと丸括弧を付けて
[-Wparentheses]
■閏年判定関数
int isleap1(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 isleap2(int year) {
if (year % 4)
return 0; //"閏年ではありません";
if (year % 100)
return 1; //"閏年です";
if (year % 400)
return 0; //"閏年ではありません";
return 1; //"閏年です";
}
早期リターンで分かりやすいかというと微妙

■1行論理式版
int isleap3(int year){
if((year%4==0 && year%100!=0) || year%400==0){
return 1; //"閏年です";
}else{
return 0; //"閏年ではありません";
}
}
論理式を一行にまとめてちょっとすっきり
■マクロ版
#define isleap4(Y) (\
((Y)%4==0 && (Y)%100!=0) || (Y)%400==0\
)
丸括弧がうるさいのであまり推奨しない
■関数版(丸括弧無し版)
static inline bool isleap5(int 西暦)
{
return 西暦%4==0 && 西暦%100!=0 || 西暦%400==0;
}
コンパイル時警告有りで非推奨
このスタイルは
聖典プログラミング言語Cでは
leap = year%4==0 && year%100!=0 || year%400==0
と紹介されています。
でも
gccやclangに丸括弧を付けてと警告されます。
ちょっと簡略化けして
leap = (x&&Y)||Z;
と
leap = X&&(Y||Z);
は、
どちらが正しいでしょうか?
この閏年判定の論理式の場合
どちらも正しいとWikipediaで
説明されています。
丸括弧の位置で動作が変わる論理式もあるので
丸括弧を付けるようにしましょう。
■丸括弧有り版:X&&(Y||Z)
static inline bool isleap6(int 西暦)
{
return 西暦%4==0 && (西暦%100!=0 || 西暦%400==0);
}
■丸括弧有り版:(X&&Y)||Z
static inline bool isleap7(int 西暦)
{
return (西暦%4==0 && 西暦%100!=0) || 西暦%400==0;
}
■まとめ(コンパイル可能)
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>
//閏年判定関数(記述量が多いので非推奨)
int isleap1(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 isleap2(int year) {
if (year % 4)
return 0; //"閏年ではありません";
if (year % 100)
return 1; //"閏年です";
if (year % 400)
return 0; //"閏年ではありません";
return 1; //"閏年です";
}
//閏年判定関数(1論理式版)
int isleap3(int year){
if((year%4==0 && year%100!=0) || year%400==0){
return 1; //"閏年です";
}else{
return 0; //"閏年ではありません";
}
}
//閏年判定マクロ(丸括弧がうるさいので非推奨)
#define isleap4(Y) (\
((Y)%4==0 && (Y)%100!=0) || (Y)%400==0\
)
//閏年判定関数(コンパイラの警告有りで非推奨)
static inline bool isleap5(int 西暦)
{
return 西暦%4==0 && 西暦%100!=0 || 西暦%400==0;
}
//閏年判定関数(X&&(Y||Z)版)
static inline bool isleap6(int 西暦)
{
return 西暦%4==0 && (西暦%100!=0 || 西暦%400==0);
}
//閏年判定関数(推奨 (X&&Y)||Z 版)
static inline bool isleap7(int 西暦)
{
return (西暦%4==0 && 西暦%100!=0) || 西暦%400==0;
}
int main(void){
for(int 西暦 = 1582 ; 西暦 <= 2038 ;西暦++){
char s[8][256];
//基本的な書き方
if(isleap1(西暦)){
sprintf(s[1],"%d年は閏年です",西暦);
} else {
sprintf(s[1],"%d年は閏年ではありません",西暦);
}
//途中経過
sprintf(s[2],"%d年は%s",西暦,isleap2(西暦)?"閏年です":"閏年ではありません");
sprintf(s[3],"%d年は%s",西暦,isleap3(西暦)?"閏年です":"閏年ではありません");
sprintf(s[4],"%d年は%s",西暦,isleap4(西暦)?"閏年です":"閏年ではありません");
sprintf(s[5],"%d年は%s",西暦,isleap5(西暦)?"閏年です":"閏年ではありません");
sprintf(s[6],"%d年は%s",西暦,isleap6(西暦)?"閏年です":"閏年ではありません");
//推奨する書き方
sprintf(s[7],"%d年は%s",
西暦,
isleap7(西暦)?
"閏年です"
:
"閏年ではありません"
);
//閏年判定結果の表示
puts(s[7]);
//検算:s[1]~s[7]まで全部同じになるはず
if(strcmp(s[1],s[2]) != 0) assert(0);
if(strcmp(s[1],s[3]) != 0) assert(0);
if(strcmp(s[1],s[4]) != 0) assert(0);
if(strcmp(s[1],s[5]) != 0) assert(0);
if(strcmp(s[1],s[6]) != 0) assert(0);
if(strcmp(s[1],s[7]) != 0) assert(0);
}
}
参考: