Menu

טיפוסי נתונים ב-C#: int, double, decimal, char, bool והטווחים שלהם

כל טיפוס מובנה של C# עם הגודל, הטווח והסיומת של הליטרל שלו, ההבדל בין טיפוסי ערך לטיפוסי הפניה, למה decimal הוא הטיפוס לכסף, גלישה של מספרים שלמים ו-checked, וערכי ברירת מחדל.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

C# היא שפה עם טיפוסים סטטיים: לכל משתנה, שדה וביטוי יש טיפוס שידוע בזמן קומפילציה. לשפה יש קבוצה של טיפוסים מובנים עם מילות מפתח משלהם (int, double, string...). כל מילת מפתח היא כינוי לטיפוס ב-namespace System, כך ש-int ו-System.Int32 הם אותו טיפוס, ו-string ו-System.String הם אותו טיפוס.

הטיפוסים המובנים

טיפוסטיפוס .NETגודלטווח או דיוקליטרל
boolBooleanבית אחדtrue או falsetrue
byteByteבית אחד0 עד 255200
sbyteSByteבית אחד-128 עד 127-5
shortInt162 בתים-32,768 עד 32,7671200
ushortUInt162 בתים0 עד 65,53560000
intInt324 בתים-2,147,483,648 עד 2,147,483,64742
uintUInt324 בתים0 עד 4,294,967,29542u
longInt648 בתיםבערך ±9.2 × 10^1842L
ulongUInt648 בתים0 עד בערך 1.8 × 10^1942ul
floatSingle4 בתיםבערך ±3.4 × 10^38, ~6 עד 9 ספרות2.5f
doubleDouble8 בתיםבערך ±1.8 × 10^308, ~15 עד 17 ספרות2.5 או 2.5d
decimalDecimal16 בתיםבערך ±7.9 × 10^28, 28 עד 29 ספרות2.5m
charChar2 בתיםיחידת קוד UTF-16 אחת, U+0000 עד U+FFFF'A'
stringStringהפניהטקסט בכל אורך, בלתי ניתן לשינוי"hello"
objectObjectהפניההבסיס של כל טיפוסnew object()

ליטרל של מספר שלם בלי סיומת הוא int, או הראשון מבין uint, long ו-ulong שיכול להכיל אותו אם הוא גדול מדי ל-int, וליטרל עם נקודה עשרונית הוא double. זו הסיבה ש-float f = 2.5; ו-decimal d = 2.5; לא עוברים קומפילציה: הליטרל הוא double, ואין המרה מרומזת מ-double ל-float או ל-decimal. הוסיפו את הסיומת: 2.5f, 2.5m.

כל טיפוס מספרי חושף את הגבולות שלו כקבועים:

פלט:

byte:  0 to 255
short: -32768 to 32767
int:   -2147483648 to 2147483647
long:  -9223372036854775808 to 9223372036854775807
decimal max: 79228162514264337593543950335
double max:  1.798E+308
sizes: int 4, long 8, double 8, char 2
255 161 3000000000

בפועל רוב הקוד משתמש בארבעה מהם: int לספירות ולאינדקסים, long למזהים ולסכומים גדולים, double למדידות ולמתמטיקה, ו-decimal לכסף.

decimal מול double

double (ו-float) מאחסנים מספרים בבינארי. לרוב השברים העשרוניים, כולל 0.1, אין צורה בינארית מדויקת, ולכן הם נשמרים כערך הקרוב ביותר שניתן לייצג, ושגיאות קטנות מצטברות. decimal מאחסן מספר שלם בבסיס 10 ועוד קנה מידה, כך ש-0.1 הוא בדיוק 0.1.

פלט:

False
True
0.30000000000000004
0.3
double sum == 1.0: False
decimal sum == 1.0: True
Total: 59.97
Split three ways: 19.99

השתמשו ב-decimal לכסף, למחירים, למס ולכל דבר שאדם יחבר ביד וישווה. הוא שומר על אפסים בסוף מהקלט שלו (1.50m מודפס כ-1.50) ויש לו 28 עד 29 ספרות משמעותיות.

השתמשו ב-double למדידות פיזיקליות, לסטטיסטיקה, לגאומטריה ולמשחקים. הוא מהיר פי כמה, משתמש בחצי מהזיכרון, והטווח שלו עצום. אף פעם אל תשוו שני doubles מחושבים עם ==; השוו את ההפרש מול סף סבילות: Math.Abs(x - y) < 1e-9.

decimal הוא לא קסם: 1m / 3m הוא עדיין 0.3333333333333333333333333333, וחשבון עם double לא זורק בחלוקה באפס (הוא מפיק אינסוף, או NaN עבור 0.0 / 0.0), בעוד שחלוקה באפס של decimal ושל מספרים שלמים זורקת DivideByZeroException.

גלישה של מספרים שלמים ו-checked

חשבון של מספרים שלמים שחורג מהטווח של הטיפוס גולש מסביב כברירת מחדל, בשקט. הקומפיילר תופס גלישה בביטויים קבועים, אבל לא כשהערכים מגיעים ממשתנים:

פלט:

-2147483648
OverflowException
-1294967296
2147483648

checked(...) או בלוק checked { ... } הופכים גלישה ל-OverflowException. אפשר גם להפעיל את זה לכל הפרויקט עם <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>. כתיבה של int x = int.MaxValue + 1; עם קבועים היא שגיאת קומפילציה (CS0220), כי הקומפיילר יכול לראות את הגלישה.

השורה האחרונה מראה את התיקון לרוב באגי הגלישה: המירו לטיפוס רחב יותר לפני החישוב. (long)(max + 1) היה שגוי, כי החיבור כבר גלש כשההמרה רצה.

טיפוסי ערך וטיפוסי הפניה

כל טיפוס ב-C# הוא טיפוס ערך או טיפוס הפניה, וההבדל קובע מה הצבה עושה.

  • טיפוסי ערך: כל הטיפוסים המספריים, bool, char, DateTime, enums, וכל struct. המשתנה מכיל את הנתונים; הצבה מעתיקה אותם.
  • טיפוסי הפניה: string, מערכים, object, וכל class. המשתנה מכיל הפניה לאובייקט; הצבה מעתיקה את ההפניה, כך ששני המשתנים רואים את אותו אובייקט.

פלט:

a=10 b=99
first[0]=99
s1=cat s2=cats

string הוא טיפוס הפניה שמתנהג בפועל כמו ערך: הוא בלתי ניתן לשינוי, ו-== משווה את הטקסט, לא את ההפניות. עוד על טיפוסי ערך שהמשתמש מגדיר ב-structs.

char ו-bool

char הוא יחידת קוד UTF-16 אחת, שנכתבת בגרשיים בודדים. מתחת לפני השטח הוא טיפוס מספרי, ולכן הוא מומר ל-int ותומך בחשבון:

פלט:

66
C
True
True
7
b
True

ל-bool יש בדיוק שני ערכים, והוא לא מומר ממספרים או אליהם: if (count) היא שגיאת קומפילציה, לא בדיקה של שונה מאפס. כתבו if (count != 0). תווים מחוץ ל-Basic Multilingual Plane, כמו רוב האימוג'י, תופסים שני ערכי char (surrogate pair), כך שה-Length של string סופר יחידות UTF-16, לא תווים נראים.

ערכי ברירת מחדל

שדות, איברי מערך ו-default(T) מקבלים את ערך ברירת המחדל של הטיפוס: אפס למספרים, false ל-bool, '\0' ל-char, ו-null לטיפוסי הפניה. משתנים מקומיים לא מקבלים ברירת מחדל, וחייבים להציב להם ערך לפני השימוש.

פלט:

0
0
False
True
0001-01-01
0,0,0

מאז C# 7.1 אפשר לכתוב את הליטרל default בלי הטיפוס כשהקומפיילר יכול להסיק אותו (int x = default;). טיפוס ערך לא יכול להיות null, ובשביל זה קיים int? (nullable value type); ראו nullable types.

מספרים שלמים בגודל נייטיב ומספרים גדולים

קיימים עוד שני טיפוסים מספריים למקרים מיוחדים. nint ו-nuint (C# 9) הם מספרים שלמים בגודל של מצביע, 32 או 64 ביט לפי הפלטפורמה, ומשמשים ב-interop ובקוד ברמה נמוכה. System.Numerics.BigInteger מחזיק מספרים שלמים בכל גודל, במחיר של מהירות:

using System.Numerics;
BigInteger factorial = 1;
for (int i = 2; i <= 30; i++) factorial *= i;
// 265252859812191058636308480000000

שאלות נפוצות

אילו טיפוסי נתונים יש ב-C#?

הטיפוסים המובנים הם המספרים השלמים (sbyte, byte, short, ushort, int, uint, long, ulong), טיפוסי הנקודה הצפה float ו-double, decimal לחשבון עשרוני מדויק, char לתו UTF-16, bool, וטיפוסי ההפניה string ו-object. כל מילת מפתח היא כינוי לטיפוס של .NET: int הוא System.Int32, string הוא System.String.

להשתמש ב-decimal או ב-double לכסף ב-C#?

השתמשו ב-decimal. double מאחסן שברים בינאריים, כך שערכים כמו 0.1 לא ניתנים לייצוג מדויק וסכומים סוטים (0.1 + 0.2 == 0.3 הוא false). decimal מאחסן ספרות בבסיס 10, שומר 28 עד 29 ספרות משמעותיות, ונותן את התוצאות שרואי חשבון מצפים להן. double מהיר יותר ויש לו טווח גדול בהרבה, אז השתמשו בו למדע, לגרפיקה ולמדידות.

מהו הערך המקסימלי של int ב-C#?

int.MaxValue הוא 2,147,483,647 ו-int.MinValue הוא -2,147,483,648 (מספר שלם של 32 ביט עם סימן). הוספת 1 ל-int.MaxValue גולשת בשקט ל-int.MinValue, אלא אם הקוד רץ בהקשר checked, ואז נזרקת OverflowException. השתמשו ב-long (עד בערך 9.2 קווינטיליון) לערכים גדולים יותר.

מה ההבדל בין float ל-double ב-C#?

float הוא 32 ביט עם בערך 6 עד 9 ספרות משמעותיות; double הוא 64 ביט עם בערך 15 עד 17. ליטרלים של נקודה צפה הם double כברירת מחדל, כך ש-float צריך את הסיומת f: float speed = 2.5f;. השתמשו ב-double אלא אם זיכרון או API (כמו Vector3 של Unity) דורשים float.

מה ההבדל בין טיפוסי ערך לטיפוסי הפניה ב-C#?

משתנה מטיפוס ערך (int, double, bool, DateTime, כל struct) מחזיק את הנתונים עצמם, והצבה מעתיקה אותם. משתנה מטיפוס הפניה (string, מערכים, כל class) מחזיק הפניה לאובייקט ב-heap, והצבה מעתיקה את ההפניה, כך ששני משתנים יכולים להצביע על אותו אובייקט.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל