PDA

View Full Version : سوال: توابع setiosflags و تابع showpoint



A_Salimi
چهارشنبه 03 مهر 1387, 17:18 عصر
سلام

چند تا سوال در مورد این توابع دارم :

1-دقیقا چه کاری رو انجام میدن ؟(با ذکر مثال لطفا)

2-این چیزایی که در msdn در تعریف فراخوانی آمده دقیقا یعنی چی ؟



T2 setiosflags(
ios_base::fmtflags _Mask
);

3-چرا فراخوانی این برنامه در یک برنامه کنسول win32 با اشکال مواجه میشه ؟ ولی در ویژوال 6 اینطوری نیست ؟

error C3861: 'setiosflags': identifier not found

و در std ها چه چیزی باید اضافه شن ؟

mic_makarti
چهارشنبه 03 مهر 1387, 18:15 عصر
سلام
1 :
http://www.cplusplus.com/reference/iostream/manipulators/setiosflags.html

2 :
http://www.cplusplus.com/reference/iostream/ios_base/fmtflags.html

3 :
http://www.programmersheaven.com/mb/CandCPP/316791/316791/c++-errors-in-program/?S=B20000

A_Salimi
چهارشنبه 03 مهر 1387, 23:03 عصر
با تشکر

در سایت cplusplus قبل از اینکه لینک بدید اینها رو دیده بودم .در هر حال ممنون میشم یکی از دوستان یک توضیح مختصر و کلی در مورد این توابع بدهند چون احساس میکنم چیزی که بصورت تجربه فرا گرفته شده راحتتر قابل فهم و بیان است تا یک متن صرفا خشک علمی که این مطلب را به صورت کلی موشکافی میکند.
در هر حال چیزی که بنظر میرسد بیشتر میتواند به یادگیری کمک کند بحث کردن روی نکات و بررسی حالات مختلف است نه صرفا اکتفا به یک یا چند لینک .

emad_67
پنج شنبه 04 مهر 1387, 00:39 صبح
setiosflags یک دستکاری کننده جریان هست که به وسیله اون و پارامتری که بهش ارسال می کنی نوع جریان خروجی رو تغییر میده.
مثلا وقتی می نویسی:


cout<<setiosflags(ios::fixed:)<<n;
این دستور در اینجا میاد جریان خروجی رو طوری تنظیم می کنه که عدد n رو به صورت نماد علمی نشون نده. یا ثابت نشون بده.
بعضی از پارامتر ها یا درواقع flag هایی که این دستور دریافت می کنه اینا هستند:

ios::left و ios::right در صورتی که از دستور setw برای تنظیم طول میدان استفاده کنید، با این فلگ می تونی جریان خروجی رو در سمت چپ یا راست میدان قرار بدی.

ios::oct و ios::dec و ios::hex برای تنظیم مبنایی که جریان خروجی باید برای نشون دادن عدد استفاده کنه.

ios::showbase مشخص می کنه که مبنای عدد در پشت اون نمایش داده بشه. مثلا برای عدد مبنای عدد موقع چاپ در پشت عدد 0 قرار می گیره و برای مبنای 16 پشت عدد 0x قرار میگیره.

ios::showpos که مشخص می کنه علامت عدد در پشت اون نشون داده بشه.

ios::scientific مشخص می کنه که اعداد در خروجی با نماد علمی نشون داده بشن.

ios::internal مشخص می کنه که در میدان کاراکتری که توسط setw ایجاد شده، علامت عدد سمت چپ میدان و خود عدد سمت راست میدان قرار بگیره. مثلا:


int a=115;
cout<<setw(10)<<setiosflags(ios::internal | ios::showpos)<<a<<endl;
در مورد showpoint هم وقتی شما یه عدد اعشاری تعریف کنی، در صورتی که از showpoint استفاده نکنی اون عدد به همون صورت نشون داده میشه مثلا:


#include<iomanip.h>
void main()
{
float a=115;
cout<<a<<endl;
}
توی خروجی همون 115 رو نشون میده. ولی وقتی بنویسی:


void main()
{
float a=115;
cout<<setiosflags(ios::showpoint)<<a<<endl;
}
توی خروجی 115.000 رو نشون میده. یعنی این فلگ باعث میشه که نقطه اعشار عدد هم نمایش داده بشه. همچنین با دستور setprecision می تونی تعداد رقم های اعشار رو هم کنترل کنی.

به جای setiosflags میشه از دستور setf هم استفاده کرد. مثلا:


float a=115;
cout.setf(ios::showpoint);
cout<<a<<endl;
همچنین در مقابل دستور setiosflags دستور resetiosflags قرار داره که به وسیله اون میشه تغییراتی که در جریان دادیم رو کنسل کنیم مثلا:


float a=115;
cout<<setiosflags(ios::showpoint)<<a<<endl;

cout<<resetiosflags(ios::showpoint)<<a<<endl;
به جای resetiosflags هم میشه از دستور unsetf استفاده کرد( مثل setf)

A_Salimi
پنج شنبه 04 مهر 1387, 13:13 عصر
چند تا سوال :




cout<<setiosflags(ios::fixed)<<n;
این دستور در اینجا میاد جریان خروجی رو طوری تنظیم می کنه که عدد n رو به صورت نماد علمی نشون نده. یا ثابت نشون بده.چرا در مورد int اینطوری نیست ؟
مثلا دستورات زیر را در نظر بگیرید :



int a=10000000;
cout<<a<<endl;
cout<<setiosflags(ios::fixed)<<a<<endl;

در صورتی که a بصورت float باشد خروجی با نماد علمی هم داریم اما الان هر دو خروجی ها بدون نماد علمی هستند.



ios::oct و ios::dec و ios::hex برای تنظیم مبنایی که جریان خروجی باید برای نشون دادن عدد استفاده کنه.

ios::showbase مشخص می کنه که مبنای عدد در پشت اون نمایش داده بشه. مثلا برای عدد مبنای عدد موقع چاپ در پشت عدد 0 قرار می گیره و برای

مبنای 16 پشت عدد 0x قرار میگیره.خوب پس برنامه زیر چه مشکلی داره که این خواسته ها رو برآورده نمکنه ؟



int main () {
int a=20;
cout<<a<<endl;
cout<<setiosflags(ios::hex|ios::showbase)<<a<<endl;
cout<<setiosflags(ios::oct|ios::showbase)<<a<<endl;
cout<<setiosflags(ios::binary|ios::showbase)<<a<<endl;
return 0;
}

طبق گفته شما الان من بایستی در خروجی اینها رو میدیدم :(البته بعلاوه علامتی که پشت اون باید قرار بگیره که من اینجا ازش صرف نظر کردم)


20
14
24
10100


اما الان من این خروجی رو دارم :


20
20
20
20+


لازمه اشاره کنم که وقتی به این صورت مینوشتم اون حرف درست در می اومد :

مثلا :



cout<<hex<<a;



ios::internal مشخص می کنه که در میدان کاراکتری که توسط setw ایجاد شده، علامت عدد سمت چپ میدان و خود عدد سمت راست میدان قرار بگیره.

مثلا:


int a=115;
cout<<setw(10)<<setiosflags(ios::internal | ios::showpos)<<a<<endl;
الان خروجی برنامه به این صورت است :


115 +


چرا خروجی به این صورت است (منظورم فاصله بین عدد و علامت است که شاید الان در محیط وب این فاصله بدرستی مشاهده نشود) و زمانی که فلگ right ویا left را اضافه میکنم این مشکل را برطرف میکند؟

با تشکر

emad_67
پنج شنبه 04 مهر 1387, 21:54 عصر
چرا در مورد int اینطوری نیست ؟
مثلا دستورات زیر را در نظر بگیرید :

کد:

int a=10000000;
cout<<a<<endl;
cout<<setiosflags(ios::fixed)<<a<<endl;


در صورتی که a بصورت float باشد خروجی با نماد علمی هم داریم اما الان هر دو خروجی ها بدون نماد علمی هستند.

چون فلگ fixed فقط برای اعداد اعشاری کاربرد داره و باعث میشه به صورت ثابت نمایش داده بشن.

خوب پس برنامه زیر چه مشکلی داره که این خواسته ها رو برآورده نمکنه ؟

کد:

int main () {
int a=20;
cout<<a<<endl;
cout<<setiosflags(ios::hex|ios::showbase)<<a<<endl;
cout<<setiosflags(ios::oct|ios::showbase)<<a<<endl;
cout<<setiosflags(ios::binary|ios::showbase)<<a<<endl;
return 0;
}


طبق گفته شما الان من بایستی در خروجی اینها رو میدیدم :(البته بعلاوه علامتی که پشت اون باید قرار بگیره که من اینجا ازش صرف نظر کردم)


20
14
24
10100


اما الان من این خروجی رو دارم :

20
20
20
20+
در این مورد منم این مشکل رو دارم، البته تا حالا بهش بر نخورده بودم ولی خروجی ئی رو که شما دریافت می کنید با من فرق داره. خروجی من اینه:


20
0x14
0x14
0x14

نمی دونم مشکل از چیه ولی وقتی با resetiosflags اون مبنایی رو که خروجی میده رو کنسل می کنم مشکل حل میشه:


cout<<a<<endl;
cout<<setiosflags(ios::hex|ios::showbase)<<a<<endl;
cout<<resetiosflags(ios::hex)<<a<<endl;
cout<<setiosflags(ios::oct|ios::showbase)<<a<<endl;

البته ios::binary رو من تاحالا ندیدم و فکر نکنم خروجی به صورت باینری داشته باشیم.

الان خروجی برنامه به این صورت است :


115 +


چرا خروجی به این صورت است (منظورم فاصله بین عدد و علامت است که شاید الان در محیط وب این فاصله بدرستی مشاهده نشود) و زمانی که فلگ right ویا left را اضافه میکنم این مشکل را برطرف میکند؟

درست متوجه این مورد نشدم، ios::internal اصلا کارش ایجاد این نوع خروجی هست( یعنی بین علامت و خود عدد فاصله میندازه). مشکلش چیه؟

A_Salimi
پنج شنبه 04 مهر 1387, 22:46 عصر
چون فلگ fixed فقط برای اعداد اعشاری کاربرد داره و باعث میشه به صورت ثابت نمایش داده بشن.اگه برای نمایش اعداد integer به صورت توان علمی هم اطلاعاتی دارید لطفا بیان کنید.


ولی خروجی ئی رو که شما دریافت می کنید با من فرق داره. خروجی من اینه:



20
0x14
0x14
0x14

بله دلیلش تفاوت کامپایلر من و شماست من هم با ویژوال سی 6 که آزمایش کردم جواب شما روگرفتم .


نمی دونم مشکل از چیه ولی وقتی با resetiosflags اون مبنایی رو که خروجی میده رو کنسل می کنم مشکل حل میشه:
جالب بود. اما در ویژوال 2008 اینطوری نیست.


البته ios::binary رو من تاحالا ندیدم و فکر نکنم خروجی به صورت باینری داشته باشیم.بله.اما در ویژوال 2008 این تابع مشاهده میشود.


درست متوجه این مورد نشدم، ios::internal اصلا کارش ایجاد این نوع خروجی هست( یعنی بین علامت و خود عدد فاصله میندازه). مشکلش چیه؟درسته – من اول فکر کردم که این خروجی مشکل داره و به صورت تصادفی flag ی که گفتم (right یا left) را اضافه کردم که در خروجی اون فاصله از بین میرفت یعنی بعد از فاصله ایجاد شده توسط setw ،علامت و عدد دقیقا کنار هم بودند(البته باز هم در :ناراحت:2008) .



int a=115;
cout<<setw(10)<<setiosflags(ios::internal | ios::showpos|ios::right)<<a<<endl;

A_Salimi
پنج شنبه 04 مهر 1387, 23:10 عصر
شرمنده ، من در پست قبل تمام تفاوت ها رو بین ویژوال 6 و 2008 عنوان کردم که دلیلش این نبود.دلیلش این بود که من برنامه ها رو در کنسول اجرا میکردم و احتمالا محیط شما کنسول نبوده .وقتی در ویژوال 6 هم یک پروژه کنسول ساختم ، همون جوابهایی رو گرفتم که در کنسول 2008 گرفته بودم !

emad_67
جمعه 05 مهر 1387, 00:25 صبح
دلیلش این بود که من برنامه ها رو در کنسول اجرا میکردم و احتمالا محیط شما کنسول نبوده
نه برای منم کنسول هست و از vc++ 6 استفاده می کنم. البته پروژه win32 باز نمی کنم.
شما این کد رو توی ویژوال 6 هم اجرا می کنی باز فاصله از بین میره؟


int a=115;
cout<<setw(10)<<setiosflags(ios::internal | ios::showpos|ios::right)<<a<<endl;

چون من همینو اجرا کردم و اون فاصله حفظ میشه. یعنی عملا ios::right انگار تاثیری نداره.

Nima_NF
جمعه 05 مهر 1387, 00:49 صبح
اشکال جای دیگری هست.

- وقتی شما از setiosflags استفاده می کنید، فقط فلگ جدید را اضافه می کنید و به فلگ های تنظیم شده قبلی کاری ندارید، پس برای اینکه فلگ جدید به درستی عمل کند باید فلگ قبلی که دیگر نیاز نیست حذف شود، یعنی در هر مرحله با استفاده از همان resetiosflags عمل پاک شدن باید انجام شود.

تابع setf شامل یک پارامتر برای تنظیم فلگ جدید و یک پارامتر دیگر برای حذف فلگ است و setiosflags فقط همین تابع setf را بدون فلگ پاک کردن فراخوانی می کند.

- چرا جواب های متفاوت بدست می آید ؟
چون فلگ قبلی را پاک نکردید.

1) برای مثال:



int a=20;
cout<<a<<endl;

cout.unsetf( ios_base::dec );
cout.setf( ios_base::hex );

cout<< a ;

پس برای hex ابتدا فلگ dec را باید پاک کرد

2) می توان به شکل زیر هم نوشت، یعنی به جای unset در پارامتر اول setf فلگ hex را اضافه کنیم و در پارامتر دوم با basefield بگوییم که فلگ پیش فرض تنظیم شده قبلی را پاک کن:




int a=20;
cout<<a<<endl;

cout.setf(ios_base::hex, ios_base::basefield );
cout<< a ;

3) راه دیگر به راحتی بدون توجه به فلگ های قبلی، فراخوانی مستقیم hex ، dec و سایر موارد هست:



int a=20;
cout<<a<<endl;

cout<< hex << a;

یعنی وقتی می نویسید hex معادل فراخوانی زیر است که عمل پاک کردن هم انجام می شود :



cout.setf(ios_base::hex,ios_base::basefield );

پس نیازی نیست همیشه از setiosflags استفاده کنید.



اگه برای نمایش اعداد integer به صورت توان علمی هم اطلاعاتی دارید لطفا بیان کنیداکثر توابع ریاضی ورودی و خروجی اعشاری دارند، اما دلیل بر این نیست که با صحیح کار نمی کنند، فقط کافیست تبدیل ضمنی انجام دهید چون بازه اعشار بیشتر است:



int b=1000;
cout<<b<<endl;
cout << fixed << (float) b << endl;


نکته:
ضمنا fixed تعداد رقم اعشار تنظیم شده ثابت شما را نمایش می دهد و نماد علمی نیست!
scientific نماد علمی هست که شما نیاز دارید.

موفق باشید

A_Salimi
جمعه 05 مهر 1387, 12:00 عصر
شما این کد رو توی ویژوال 6 هم اجرا می کنی باز فاصله از بین میره؟

نه همونطوری که گفتم فقط در کنسول win32 در هر ورژنی این اتفاق می افته .


- وقتی شما از setiosflags استفاده می کنید، فقط فلگ جدید را اضافه می کنید و به فلگ های تنظیم شده قبلی کاری ندارید، پس برای اینکه فلگ جدید به درستی عمل کند باید فلگ قبلی که دیگر نیاز نیست حذف شود، یعنی در هر مرحله با استفاده از همان resetiosflags عمل پاک شدن باید انجام شود.

خوب در بالا هم این بحث شد ولی همونطوری که گفتم **
چون فلگ قبلی را پاک نکردید.** دلیل نمیشود !

اصلا شما این رو بگید كه برنامه نویسی در کنسول با حالت معمول چه تفاوتی دارد (فرضا با بورلند) و برنامه های کنسول چه ویژگی را ایجاد میکنند که غیر کنسول آن را برآورده نمیکنند ؟
ببخشید که حرف قبلی رو تکرار میکنم اما با اینکه resetiosflags هم فراخوانی شد در پروژه کنسول خواسته ما برطرف نشد و در زیر جوابهایی که از اجرای کدهای زیر گرفتم را دوباره می آورم :



int main(){
int a=20;
cout<<a<<endl;
cout<<setiosflags(ios::hex|ios::showbase)<<a<<endl;
cout<<resetiosflags(ios::hex)<<a<<endl;
cout<<setiosflags(ios::oct|ios::showbase)<<a<<endl;
return 0;
}


در کنسول :
20
20
20
20
معمولي :
20
0×14
20
024

مشکل کد بالا دقيقا چيست؟

ولی این کدهایی که گذاشتید جالب بودند :



int a=20;
cout<<a<<endl;

cout.unsetf( ios_base::dec );
cout.setf( ios_base::hex );

cout<< a ;


و من یک نکته مهم رو فرا گرفتم و اون اینکه وقتی با setiosflags خروجی رو ست میکنیم یک حالت overload پیش میاد و تا آخر برنامه خروجی hex خواهد بود.


راه دیگر به راحتی بدون توجه به فلگ های قبلی، فراخوانی مستقیم hex ، dec و سایر موارد هست:



int a=20;
cout<<a<<endl;

cout<< hex << a;



آیا برای باینری هم دستوری وجود دارد ؟ من bin وbinary رو چک کردم که جواب نگرفتم و برنامه خطا داد.(با اینکه در لیست ظاهر شده پس از ios:: ، binary وجود دارد.)

Nima_NF
جمعه 05 مهر 1387, 14:16 عصر
خوب در بالا هم این بحث شد ولی همونطوری که گفتم **** دلیل نمیشود !
اصلا شما این رو بگید كه برنامه نویسی در کنسول با حالت معمول چه تفاوتی دارد (فرضا با بورلند) و برنامه های کنسول چه ویژگی را ایجاد میکنند که غیر کنسول آن را برآورده نمیکنند ؟
ابتدا اینکه این توابع جز استاندارد C هستند و فقط محیط کنسول نیستند.
شما می توانید به جای cout یک فایل داشته باشید و اطلاعات در فایل ذخیره شود و با کامپایل آن با کامپایلرهای مختلف قابل اجرا در همه سیستم عامل ها. حال این فایل می تواند در برنامه های GUI ویندوز، لینوکس و غیره استفاده شود.

اشکال دیگر اینجاست که من چند روش به شما گفتم و شما سخت ترین، کم کاربردترین و سطح پایین ترین آن ها یعنی setiosflags را انتخاب کردید، پس باید همه چیز را خودتان کنترل کنید.

پس به پست قبل برگردید و مثال 3 را مجددا مطالعه کنید، نمونه دیگر:



cout << showbase << a << endl; // dec is default
cout << hex << a << endl;
cout << oct << a << endl;

cout << hex << noshowbase << a << endl;

تاکید مجدد: یعنی تا جایی که نیاز ندارید مستقیم از setiosflags استفاده نکنید، با نوشتن مستقیم آن اسامی مانند hex و ... خودش تابع setf را فراخوانی می کند و فلگ قبلی را پاک می کند. نمی دانم چرا اصرار بر setiosflags دارید!






ببخشید که حرف قبلی رو تکرار میکنم اما با اینکه resetiosflags هم فراخوانی شد در پروژه کنسول خواسته ما برطرف نشد و در زیر جوابهایی که از اجرای کدهای زیر گرفتم را دوباره می آورم ....
مشکل کد بالا دقيقا چيست؟
شما کد را اشتباه نوشتید و باید این طوری باشد تا درست عمل کند:



cout<<a<<endl;
cout<<resetiosflags(ios::dec);
cout<<setiosflags(ios::hex|ios::showbase)<<a<<endl;
cout<<resetiosflags(ios::hex);
cout<<setiosflags(ios::oct|ios::showbase)<<a<<endl;

همانطور که گفتم اگر طبق مثال قبلی عمل کنید(بدون setiosflags) اصلا لازم نیست وارد جزییات شوید.



آیا برای باینری هم دستوری وجود دارد ؟
اول این سوال پیش می آید چرا اصلا از این روش های کم کاربرد برای تبدیل استفاده می کنید؟

توابع ریاضی و تبدیل داده ها در اختیار شما است، چرا از itoa (در vc با itoa_ و itoa_s) یا sprintf یا امثال آن استفاد نمی کنید. با این توابع می توانید در هر مبنایی بین 2 تا 32 تبدیل انجام دهید(حال در کنسول یا در سایر محیط های 32 یا 64 بیت)، مثلا برای باینری:



<stdlib.h>

char str[33];
_itoa( a , strr, 2 );