اجتماع مانند ساختار دادههایی است که از چند عضو تشکیل میشود و هر عضو آن نوع دادهای منحصر به خود دارد. اجتماع محلی از حافظه است که چندین متغیر در آن قرار میگیرند که ممکن است نوع آنها نیز یکسان نباشد. در واقع اجتماع متغیری است که امکان ذخیره کردن انواع مختلف داده در مکان مشترکی از حافظه را فراهم میکند.
تعریف اجتماع مشابه تعریف ساختار است با این تفاوت که در اجتماع تمام اعضای تشکیلدهنده آن فضایی را به صورت اشتراکی اشغال میکنند (برخلاف ساختار که هر عضو آن محل حافظه یا مکان خاص خودش را داراست)، از این رو به منظور صرفهجویی در حافظه به کار گرفته میشود. این گونه ساختمان دادهها در کاربردهایی مفیدند که اعضای چندگانه از نوع مختلف دارند، ولی در هر زمان باید فقط به یکی از این اعضا مقداری نسبت داد. به هرحال کاربر باید بداند که هر لحظه چه نوع داده در حافظه مشترک مورد نظر ذخیره شده است.
در حالت کلی ترکیب اجتماع ممکن است به صورت زیر تعریف شود.
union tag {
member 1 ;
member 2 ;
…
…
…
member m ;
} ;
که در آن union کلمهای کلیدی است.
مثال به تعریف زیر توجه کنید.
union union_type {
int i ;
char ch ;
} ;
این تعریف نیز مشابه تعریف ساختار، موجب توصیف یا اعلان متغیر نمیگردد، بلکه فقط تعریف نوع داده است. برای اعلان هر متغیری از نوع اجتماع مورد نظر، باید نام آن را به دنبال تعریف union به کار برد یا به طور جداگانه آن را اعلان کرد. پس روش اعلان متغیرهایی از نوع اجتماع مشابه اعلان از نوع ساختار است.
با توجه به مطالب بالا، متغیر x به دو روش اعلان شده است که نتیجه نهایی هر دو همارز است.
روش اول روش دوم
union tag {
int i ;
char ch ;
} ;
union tag x ; union tag {
int i ;
char ch ;
} x ;
در اینجا، متغیرهای i و ch که به ترتیب از نوع int و char اند، حافظه مشترک دارند که البته متغیر i دو بایت و متغیر ch یک بایت حافظه اشغال میکند، ولی آدرس شروع آنها یکسان است (شکل ۹ـ۲).
نحوه اشغال حافظه مشترک با دو عضو اجتماع:
وقتی که اجتماع اعلام میگردد، کامپایلر به طور خودکار متغیری که بتواند بزرگترین عضو اجتماع را در خود جای دهد ایجاد میکند که در مثال بالا بزرگی آن ۲ بایت است.
باتوجه به مطالبی که گفتیم، شکل کلی اعلان متغیرهایی از نوع اجتماع به صورت زیر است.
storage _ class union tag variable1 ,variable 2 , … , variable n ;
که در آن storage_class گزینه اختیاری است که اگر به کار نبریم حافظه مورد نظر از کلاس خودکار خواهد بود.
به طوری که گفتیم، میتوان اعلان متغیرهایی از نوع اجتماع را به دنبال تعریف اجتماع به کار برد. پس میتوان صورت بالا را چنین تعریف کرد.
storage_class union tag {
member 1 ;
member 2 ;
…
…
…
member m ;
} variable 1 , variable 2 , … , variable n ;
مثال به اعلان زیر توجه کنید.
union id {
char color [12] ;
int size ;
} shirt , blouse ;
در این مثال، دو متغیر shirt و blouse از نوع اجتماعاند که با نام id تعریف شده است. هرکدام از این دو متغیر در هر لحظه یا معرف رشته ۱۲ کاراکتری color یا معرف مقدار صحیح size خواهد بود. بدیهی است چون رشته مزبور ۱۲ کاراکتری است و به حافظه بیشتری در مقایسه با size نیاز دارد، کامپایلر، به طور خودکار، ۱۲ بایت حافظه به هر متغیر اجتماع اختصاص خواهد داد.
اجتماع ممکن است عضوی از ساختار باشد. همچنین ساختار ممکن است عضوی از اجتماع باشد.
مثال تعریف زیر را در نظر بگیرید.
union id {
char color[12] ;
int size ;
struct clothes {
char manufacturer[20] ;
float cost ;
union id description ;
} shirt , blouse ;
}
در این مثال دو متغیر shirt و blouse متغیرهایی از نوع ساختارند که با نام clothes تعریف شدهاند و هرکدام از آنها شامل اعضای زیر است: رشتهای به نام manufacturer (نام تولیدکننده لباس)، مقداری از نوع اعشار به نام cost (معرف بهای لباس) و اجتماعی به نام description (نوع لباس). در اینجا ممکن است که اجتماع معرف رشته یا color یا معرف مقدار صحیح یا size باشد. راه دیگری برای مشخص ساختن (اعلان) متغیرهای ساختار shirt و blouse آن است که دو نوع اعلان بالا را با یکدیگر ترکیب کنیم و بهصورت فشردهتر زیر بنویسیم.
struct clothes {
char manufacturer[20] ;
float cost ;
union {
char color[12] ;
int size ;
} description ;
} shirt , blouse ;
نحوه دستیابی به عناصر یا اعضای اجتماع مشابه همان است که در مورد ساختارها گفتیم؛ یعنی این کار با استفاده از دو عملگر `.’ و `->’ انجام میگیرد. بنابراین اگر variable متغیر اجتماع باشد دستور variable. member یک عضو آن را معرفی و مشخص میکند. به طریق مشابه، اگر ptvar متغیر اشارهگر باشد که به اجتماع اشاره میکند، (یعنی آدرس متغیری از نوع اجتماع را در خود دارد) در این صورت ptvar->member به یک عضو آن اجتماع اشاره خواهد کرد.
مثال برنامه ساده زیر را درنظر بگیرید.
# include < stdio. h>
main ()
{
union id {
char color ;
int size ;
} ;
struct {
char manufacturer[20] ;
float cost ;
union id description ;
} shirt , blouse ;
printf (“%d\n” , sizeof (union id)) ;
shirt. description. color = `w’ ; /* assign a value to color */
printf (“%c %d \n” , shirt. description. color , shirt. description. size) ;
shirt. description. size = 12 ; /* assign a value to size */
printf (“%c %d\n” , shirt. description. color , shirt. description. size) ;
}
در این مثال، اولین عضو اجتماع تککاراکتری است، برخلاف مثال قبلی که آرایهای ۱۲ کاراکتری بود. انجام این تغییرات بدین لحاظ صورت گرفته که نسبت دادن مقادیر به اعضای اجتماع آسانتر باشد.
ملاحظه میکنید که به عضو shirt. description. Color مقدار `w’نسبت داده شده است. پس باید توجه داشته باشید که عضو دیگر اجتماع، یعنی shirt. Description مقدار معنی نخواهد داشت. سپس با دستور printf، مقدار هر دو عضو اجتماع نمایش داده شده است. سپس به عضو shirt. description. size مقدار ۱۲ نسبت داده شده است. بدیهی است که این مقدار، روی مقدار حافظه مشترک که برای دو عضو مزبور پیشبینی شده است خواهد نشست. سپس بار دیگر با دستور printf مقدار هر عضو نمایش داده شده است.
خروجی برنامه مزبور به شکل زیر است.
۲
w-24713
@ ۱۲
سطر اول نشان میدهد که ۲ بایت حافظه به اجتماع اختصاص داده شده است تا بتواند بزرگترین عضو خود را که مقدار صحیح است در خود جای دهد. در سطر دوم، داده اولی `w’ است که معنی و مفهوم دارد. اما داده دوم، یعنی ۲۴۷۱۳-، معنی و مفهومی ندارد. در سطر سوم، داده اولی @ است که بدون معنی است. اما داده دوم که ۱۲ است معنی و مفهوم دارد.