このような変数の最大値を返す C の関数はありますか (以下の例では関数に「maxvalue」という名前を付けます)。
int a;
printf("%d", maxvalue(a)); // 32767
unsigned int b;
printf("%d", maxvalue(b)); // 65535
したがって、基本的に、関数はINT_MAX
、変数がsigned INTの場合、unsigned intの場合はUINT_MAXなどの値を返します。
このような変数の最大値を返す C の関数はありますか (以下の例では関数に「maxvalue」という名前を付けます)。
int a;
printf("%d", maxvalue(a)); // 32767
unsigned int b;
printf("%d", maxvalue(b)); // 65535
したがって、基本的に、関数はINT_MAX
、変数がsigned INTの場合、unsigned intの場合はUINT_MAXなどの値を返します。
このような関数は、C 標準ライブラリでは定義されていません。それを計算するマクロを定義してみることができます:
#define MAX_VALUE(a) (((unsigned long long)1 << (sizeof(a) * CHAR_BIT)) - 1)
使用する場合は、十分な大きさの型に割り当てられていることに注意してください。例えば:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#define IS_TYPE_SIGNED(a) ((a-1) < 0)
#define MAX_VALUE_UNSIGNED(a) (((unsigned long long)1 << \
(sizeof(a) * CHAR_BIT)) - 1)
#define MAX_VALUE_SIGNED(a) (MAX_VALUE_UNSIGNED(a) >> 1)
#define MAX_VALUE(a) (IS_TYPE_SIGNED(a) ? \
MAX_VALUE_SIGNED(a) : MAX_VALUE_UNSIGNED(a))
int main(void)
{
unsigned int i = 0;
signed int j = 0;
printf("%llu\n", MAX_VALUE(i));
printf("%llu\n", MAX_VALUE(j));
return EXIT_SUCCESS;
}
これは出力します:
4294967295
2147483647
C11 型ジェネリック式を使用すると、非常に簡単に実行できます。
#define maxvalue(type) _Generic(type, int: INT_MAX, \
unsigned int: UINT_MAX)
それは機能ではありませんが、あなたが望むことをすると思います。簡単なプログラム例を次に示します。
#include <stdio.h>
#include <limits.h>
#define maxvalue(type) _Generic(type, int: INT_MAX, \
unsigned int: UINT_MAX)
int main(void)
{
int i;
unsigned int ui;
printf("%u\n", maxvalue(i));
printf("%u\n", maxvalue(ui));
return 0;
}
そしてその出力:
$ clang -Wall -Werror -Wextra -pedantic -std=c11 example.c -o example
$ ./example
2147483647
4294967295
私のシステムには 32 ビット整数があるため、私の回答はあなたの回答よりも大きくなっています。16 ビット マシンを使用しているようです。
変数ではなく型に対して機能する私のライブラリのマクロを次に示します。
/* min and max integer values. T is a signed or unsigned integer type. */
/* Returns 1 if T is signed, else 0. */
#define INTTYPE_SIGNED(T) ((T)-1 < (T)0)
/*
* Returns (T)(maximum value of a T).
*
* Pains are taken (perhaps unnecessarily) to avoid integer overflow
* with signed types.
*/
#define INTTYPE_MAX(T) \
(((T)1 << (CHAR_BIT*sizeof(T)-INTTYPE_SIGNED(T)-1)) - 1 + \
((T)1 << (CHAR_BIT*sizeof(T)-INTTYPE_SIGNED(T)-1)))
/*
* Returns (T)(minimum value of a T).
* Pains are taken (perhaps unnecessarily) to avoid integer overflow
* with signed types.
* assert: twos complement architecture
*/
#define INTTYPE_MIN(T) ((T)(-INTTYPE_MAX(T)-1))
編集:これらを質問に適応させる:
/* min and max integer values. V is a signed or unsigned integer value. */
/* Returns 1 if V has signed type, else 0. */
#define INT_VALUE_SIGNED(V) ((V)-(V)-1 < 0)
/*
* Returns maximum value for V's type.
*
* Pains are taken (perhaps unnecessarily) to avoid integer overflow
* with signed types.
*/
#define INT_VALUE_MAX(V) \
(((V)-(V)+1 << (CHAR_BIT*sizeof(V)-INT_VALUE_SIGNED(V)-1)) - 1 + \
((V)-(V)+1 << (CHAR_BIT*sizeof(V)-INT_VALUE_SIGNED(V)-1)))
/*
* Returns minimum value for V's type.
* Pains are taken (perhaps unnecessarily) to avoid integer overflow
* with signed types.
* assert: twos complement architecture
*/
#define INT_VALUE_MIN(V) (-INT_VALUE_MAX(V)-1)
後付け: これらは、V が変数、または値が割り当てられていない変数を含む式である場合に UB を呼び出します...これは、尋ねられた質問の場合です。それらは多くの実装で動作する可能性がありますが、C 標準はそれを保証しておらず、初期化されていない変数をトラップ値で初期化する実装では確実に失敗します。
ANSI C 89 を使用して簡単に実行できます。
#include<stdio.h>
#include<limits.h>
int main(void) {
printf("Max value of char: %d\n", CHAR_MAX);
printf("Min value of char: %d\n", CHAR_MIN);
printf("Max value of short: %d\n", SHRT_MAX);
printf("Min value of short: %d\n", SHRT_MIN);
printf("Max value of int: %d\n", INT_MAX);
printf("Min value of int: %d\n", INT_MIN);
printf("\n\n");
return 0;
}
float.h をインクルードしてから以下を使用できることに注意してください。
printf("Max value of Double: %d\n", DBL_MAX);
ただし、あまりお勧めしません。
がんばれ、ロン
いいえ、そのような関数は標準の C 実装には存在しません。
これを行う関数を作成することはできませんが、これを行ういくつかのマクロを作成できます。
C11 を使用している場合は、_Genericを使用できます。
#define maxvalue(x) \
_Generic(x, \
char: 127, short: 32767, int: INT_MAX, \
unsigned char: 255, unsigned short: 65535, unsigned int: UINT_MAX)
C89 が必要な場合は、署名付き/未署名を区別できる場合に実行できます。
#define maxvalue_unsigned(x) ((1<<(8*sizeof(x)))-1)
#define maxvalue_signed(x) ((1<<((8*sizeof(x)-1)))-1)
typename を要求する (または GCC 固有のtypename
を使用する) 場合は、文字列を使用できます。
#define maxvalue_type(x) maxvalue_helper(#x "----------")
unsigned long long maxvalue_helper(const char *s) {
switch(*s){
char 'c': /* char */ return 127;
char 's': /* short */ return 32767;
char 'i': /* int */ return INT_MAX;
/* ... */
case 'u': /* unsigned */
switch(9[s]) {
case 'c': /* unsigned char */ return 255;
char 's': /* unsigned short */ return 65535;
char 'i': /* unsigned int */ return UINT_MAX;
/* ... */
変数の値を変更、比較、および復元することによって、指定された整数変数が署名されているかどうかをテストする、比較的使いやすいマクロ を思い付くことができたようSIGNED_VAR(VAR)
です (これは、 より小さい型にのみ必要ですint
) 。未定義の動作、特に符号付きオーバーフローとシーケンス ポイントに関連する種類の動作を回避します。というかそうらしい。少なくとも、gcc ( で起動) は、演算子と演算子-Wall
の間でおかしなことをしているのに文句を言うことはありません。&&
||
?:
このマクロの良い点は、C89 および C99 コンパイラで動作1LL
することです ( C89 コンパイラに C99 の拡張型がない場合は、 と置き換え可能であり、単に (そしてもちろん)1L
とlong long
置き換えることができますlong
) "%ll"
。(および)より小さい型を正しくサポートします。"%l"
long long
int
char
short
変数が符号付きかどうかがわかれば、最小値と最大値を構築するのは簡単で、多くの人がその方法を示しています。マクロVAR_MAX()
とVAR_MIN()
はこれらの値を構築し、最長の C99 整数型 として返しますlong long
。符号なしの値を符号付きに変換する際の潜在的なオーバーフロー/UB の問題を回避するために、符号付きの型を返すことにしました。返される型は( )long long
の最大値を符号付きの値として直接表すことができないため、その値を返す必要がある場合は、代わりに -1 が返されます。ここで少し注意が必要です。unsigned long long
ULLONG_MAX
unsigned long long
ULLONG_MAX
これが醜さです。バグを見逃さなかったことを願っています。
ああ、もちろん、2 の補数値の非対称範囲全体が符号付きの型でサポートされていることが期待されます (例: min=-128、max=+127)。
編集SIGNED_VAR()
:変数が初期化されることを期待していることを忘れていました。そうしないと、それを読み取ると、未定義の動作が発生する可能性があります。
// file: IntVarMinMax.c
// compile: gcc -Wall -std=c99 -O2 IntVarMinMax.c -o IntVarMinMax.exe
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int SignTestTestVal;
unsigned char SignTestOriginalXchar;
unsigned short SignTestOriginalXshort;
signed char SignTestRestoreOriginalXchar(void)
{
if (SignTestOriginalXchar < SCHAR_MAX + 1u)
return (signed char)SignTestOriginalXchar;
return (signed char)(SignTestOriginalXchar - SCHAR_MAX - 1) - SCHAR_MAX - 1;
}
short SignTestRestoreOriginalXshort(void)
{
if (SignTestOriginalXshort < SHRT_MAX + 1u)
return (short)SignTestOriginalXshort;
return (short)(SignTestOriginalXshort - SHRT_MAX - 1) - SHRT_MAX - 1;
}
#define IFELSE(E1,E2,E3) (((E1) && (E2)) || (!(E1) && (E3)))
#define SEQ(E1,E2) (((E1) && (E2)) || (E2))
#define SIGNED_VAR(VAR) \
( \
IFELSE \
( \
sizeof(VAR) >= sizeof(int), \
((VAR) - (VAR) - 1 < 0), \
IFELSE \
( \
sizeof(VAR) == sizeof(short), \
SEQ(SignTestOriginalXshort = (VAR), \
SEQ(SignTestTestVal = (VAR) = -1, \
SEQ((VAR) = SignTestRestoreOriginalXshort(), \
SignTestTestVal < 0))), \
IFELSE \
( \
sizeof(VAR) == sizeof(char), \
SEQ(SignTestOriginalXchar = (VAR), \
SEQ(SignTestTestVal = (VAR) = -1, \
SEQ((VAR) = SignTestRestoreOriginalXchar(), \
SignTestTestVal < 0))), \
(fprintf(stderr, "unsupported type!"), exit(-1), 0) \
) \
) \
) \
)
#define VAR_MAX(SIGNED,VAR) \
( \
SIGNED ? \
((1ll << (sizeof(VAR) * CHAR_BIT - 2)) - 1 + \
(1ll << (sizeof(VAR) * CHAR_BIT - 2))) : \
( \
(sizeof(VAR) < sizeof(long long)) ? \
((1ll << (sizeof(VAR) * CHAR_BIT - 1)) - 1 + \
(1ll << (sizeof(VAR) * CHAR_BIT - 1))) : \
( \
(sizeof(VAR) == sizeof(long long)) ? \
-1ll : \
(fprintf(stderr, "unsupported type!"), exit(-1), 0) \
) \
) \
)
#define VAR_MIN(SIGNED,VAR) \
( \
SIGNED ? \
(-((1ll << (sizeof(VAR) * CHAR_BIT - 2)) - 1 + \
(1ll << (sizeof(VAR) * CHAR_BIT - 2))) - 1) : \
0 \
)
int main(void)
{
signed char sc = 1; char c = 2; unsigned char uc = 3;
short ss = 4; unsigned short us = 5;
int si = 6; unsigned int ui = 7;
long sl = 8; unsigned long ul = 9;
long long sll = 10; unsigned long long ull = 11;
#define PRINT_VARS() \
printf("sc=%hhd, c=%hhu, uc=%hhu, " \
"ss=%hd, us=%hu, si=%d, ui=%u, " \
"sl=%ld, ul=%lu, sll=%lld, ull=%llu\n", \
sc, c, uc, \
ss, us, si, ui, \
sl, ul, sll, ull)
#define TEST_VAR(VAR) \
{ \
int varIsSigned = SIGNED_VAR(VAR); \
if (varIsSigned) \
printf("%lld <= " #VAR " <= %lld\n", \
VAR_MIN(varIsSigned,VAR), \
VAR_MAX(varIsSigned,VAR)); \
else \
printf("%lld <= " #VAR " <= %llu\n", \
VAR_MIN(varIsSigned,VAR), \
(unsigned long long)VAR_MAX(varIsSigned,VAR)); \
}
PRINT_VARS();
TEST_VAR(sc);
TEST_VAR(c);
TEST_VAR(uc);
TEST_VAR(ss);
TEST_VAR(us);
TEST_VAR(si);
TEST_VAR(ui);
TEST_VAR(sl);
TEST_VAR(ul);
TEST_VAR(sll);
TEST_VAR(ull);
PRINT_VARS();
return 0;
}
出力 ( ideone ):
sc=1, c=2, uc=3, ss=4, us=5, si=6, ui=7, sl=8, ul=9, sll=10, ull=11
-128 <= sc <= 127
-128 <= c <= 127
0 <= uc <= 255
-32768 <= ss <= 32767
0 <= us <= 65535
-2147483648 <= si <= 2147483647
0 <= ui <= 4294967295
-2147483648 <= sl <= 2147483647
0 <= ul <= 4294967295
-9223372036854775808 <= sll <= 9223372036854775807
0 <= ull <= 18446744073709551615
sc=1, c=2, uc=3, ss=4, us=5, si=6, ui=7, sl=8, ul=9, sll=10, ull=11