ฉันเคยเห็นรูปแบบนี้ใช้มากใน C & C ++
unsigned int flags = -1; // all bits are true
นี่เป็นวิธีพกพาที่ดีในการทำสิ่งนี้หรือไม่? หรือใช้อยู่0xffffffff
หรือ~0
ดีกว่า?
ฉันเคยเห็นรูปแบบนี้ใช้มากใน C & C ++
unsigned int flags = -1; // all bits are true
นี่เป็นวิธีพกพาที่ดีในการทำสิ่งนี้หรือไม่? หรือใช้อยู่0xffffffff
หรือ~0
ดีกว่า?
-1
จะใช้งานได้ตลอดเวลา แต่ความจริงที่ว่าจำเป็นต้องแสดงความคิดเห็นหลังจากนั้นแสดงว่ารหัสนั้นไม่ชัดเจน หากตัวแปรถูกกำหนดให้เป็นชุดของแฟล็กเหตุใดจึงกำหนดให้เป็นจำนวนเต็ม ประเภทของมันอาจเป็นจำนวนเต็ม แต่ไม่ใช่จำนวนเต็มตามความหมาย คุณจะไม่เพิ่มหรือคูณมัน ดังนั้นฉันจะ0xffffffff
ไม่ใช้เพื่อการพกพาหรือความถูกต้อง แต่เพื่อความชัดเจน
-1
ยังคงเป็นโซลูชันแบบพกพาและใช้งานร่วมกันได้สำหรับทั้งสองภาษา แต่อาจส่งผลต่อเหตุผลบางประการในคำตอบอื่น ๆ
คำตอบ:
ฉันขอแนะนำให้คุณทำตามที่คุณได้แสดงไว้เนื่องจากเป็นวิธีที่ตรงไปตรงมาที่สุด เริ่มต้น-1
ที่จะใช้งานได้ตลอดเวลาโดยไม่ขึ้นกับการแสดงสัญลักษณ์จริงในขณะที่~
บางครั้งจะมีพฤติกรรมที่น่าแปลกใจเนื่องจากคุณจะต้องมีประเภทตัวถูกดำเนินการที่ถูกต้อง จากนั้นคุณจะได้รับมูลค่าที่สูงที่สุดของunsigned
ประเภท
สำหรับตัวอย่างของความประหลาดใจที่เป็นไปได้ให้พิจารณาสิ่งนี้:
unsigned long a = ~0u;
ไม่จำเป็นต้องเก็บรูปแบบที่มีบิต 1 a
ทั้งหมด แต่มันเป็นครั้งแรกที่จะสร้างรูปแบบกับบิตทั้ง 1 แห่งในอีกด้วยและจากนั้นกำหนดให้unsigned int
a
จะเกิดอะไรขึ้นเมื่อunsigned long
มีบิตมากขึ้นนั่นไม่ใช่ทั้งหมดที่เป็น 1
และพิจารณาสิ่งนี้ซึ่งจะล้มเหลวในการเป็นตัวแทนเสริมที่ไม่ใช่สอง:
unsigned int a = ~0; // Should have done ~0u !
เหตุผลก็คือ~0
ต้องกลับบิตทั้งหมด การเปลี่ยนกลับที่จะให้ผล-1
กับเครื่องเสริมของทั้งสอง (ซึ่งเป็นค่าที่เราต้องการ!) แต่จะไม่ให้ผล-1
กับการแสดงอื่น บนเครื่องเติมเต็มหนึ่งเครื่องให้ผลเป็นศูนย์ ดังนั้นบนเครื่องเสริมของหนึ่งเครื่องข้างต้นจะเริ่มต้นa
เป็นศูนย์
สิ่งที่คุณควรเข้าใจคือทุกอย่างเกี่ยวกับค่าไม่ใช่บิต ตัวแปรที่จะเริ่มต้นกับความคุ้มค่า หากใน initializer คุณแก้ไขบิตของตัวแปรที่ใช้สำหรับการเริ่มต้นค่าจะถูกสร้างขึ้นตามบิตเหล่านั้น ค่าที่คุณต้องการที่จะเริ่มต้นa
กับค่าเป็นไปได้สูงสุดเป็นหรือ-1
UINT_MAX
อย่างที่สองจะขึ้นอยู่กับประเภทของa
- คุณจะต้องใช้ULONG_MAX
สำหรับunsigned long
ไฟล์. อย่างไรก็ตามวิธีแรกจะไม่ขึ้นอยู่กับประเภทของมันและเป็นวิธีที่ดีในการได้รับมูลค่าสูงสุด
เราไม่ได้พูดถึงว่า-1
มีบิตทั้งหมดหรือไม่ (ไม่ได้มีเสมอไป) และเราไม่ได้พูดถึงว่า~0
มีบิตทั้งหมดหรือไม่(มีแน่นอน)
แต่สิ่งที่เรากำลังพูดถึงคือผลลัพธ์ของflags
ตัวแปรเริ่มต้นคืออะไร และมันเพียง แต่-1
จะทำงานร่วมกับทุกประเภทและเครื่องจักร
numeric_limits<size_t>::max()
ค่อนข้างยืดเยื้อ แต่นักแสดงก็เช่นกัน ...
-1
แสดงโดยและไม่ถามว่าบิต~0
มีอะไรบ้าง เราอาจไม่สนใจเกี่ยวกับค่าต่างๆ แต่คอมไพเลอร์ทำ เราไม่สามารถเพิกเฉยต่อความจริงที่ว่าการดำเนินการทำงานร่วมกับค่านิยม ค่าของ~0
อาจจะไม่-1
แต่นี้เป็นค่าที่คุณต้องการ ดูคำตอบของฉันและสรุปของ @ Dingo
unsigned int flags = -1;
เป็นแบบพกพาunsigned int flags = ~0;
ไม่สามารถพกพาได้เนื่องจากต้องอาศัยการแสดงสองส่วนเสริมunsigned int flags = 0xffffffff;
ไม่สามารถพกพาได้เนื่องจากถือว่า ints 32 บิตหากคุณต้องการตั้งค่าบิตทั้งหมดในแบบที่รับรองโดยมาตรฐาน C ให้ใช้บิตแรก
~0
แน่นอนว่าให้int
ค่ากับชุดบิตทั้งหมด แต่การกำหนด an int
ให้unsigned int
ไม่จำเป็นต้องส่งผลให้ int ที่ไม่ได้ลงนามมีรูปแบบบิตเดียวกับรูปแบบบิตที่ลงนาม เฉพาะการแสดงส่วนเสริมของ 2 เท่านั้นที่เป็นเช่นนี้เสมอ ในการแสดงส่วนเติมเต็มหรือขนาดเครื่องหมาย 1 วินาทีให้กำหนดint
ค่าลบให้กับunsigned int
ผลลัพธ์ในรูปแบบบิตอื่น เนื่องจากมาตรฐาน C ++ กำหนดให้การแปลงที่ลงชื่อ -> ไม่ได้ลงชื่อเป็นค่าโมดูโลเท่ากันไม่ใช่ค่าที่มีบิตเดียวกัน
ตรงไปตรงมาฉันคิดว่า fff ทั้งหมดอ่านได้มากกว่า สำหรับความคิดเห็นที่ว่ามันเป็นแอนติแพตเทิร์นถ้าคุณสนใจจริงๆว่าบิตทั้งหมดถูกตั้งค่า / เคลียร์ฉันขอยืนยันว่าคุณอาจอยู่ในสถานการณ์ที่คุณสนใจขนาดของตัวแปรอยู่แล้วซึ่งจะเรียกร้องให้มีบางอย่างเช่นบูสต์ :: uint16_t ฯลฯ
วิธีที่หลีกเลี่ยงปัญหาที่กล่าวถึงคือทำ:
unsigned int flags = 0;
flags = ~flags;
พกพาได้และตรงประเด็น
flags
const
~0
คือจำนวนเต็มที่มีการตั้งค่าบิตทั้งหมดเป็น 1 แต่เมื่อคุณกำหนดสิ่งนั้นint
ให้กับunsigned
ตัวแปรflags
คุณจะทำการแปลงค่าจาก-2**31
(สมมติว่าเป็น 32 บิตint
) (-2**31 % 2**32) == 2**31
ซึ่งเป็นจำนวนเต็ม ด้วยบิตทั้งหมด แต่ชุดแรกเป็น 1
u
คำต่อท้ายในคำตอบของคุณ แน่นอนว่าจะใช้งานได้ แต่ยังคงมีปัญหาในการระบุประเภทข้อมูลที่คุณใช้ ( unsigned
และไม่ใหญ่กว่า) สองครั้งซึ่งอาจนำไปสู่ข้อผิดพลาด ข้อผิดพลาดมักจะปรากฏขึ้นหากการกำหนดและการประกาศตัวแปรเริ่มต้นอยู่ห่างกันมากขึ้น
ฉันไม่แน่ใจว่าการใช้ int ที่ไม่ได้ลงชื่อสำหรับแฟล็กเป็นความคิดที่ดีตั้งแต่แรกใน C ++ แล้วบิตเซ็ตล่ะ?
std::numeric_limit<unsigned int>::max()
จะดีกว่าเพราะ0xffffffff
สมมติว่า int ที่ไม่ได้ลงชื่อเป็นจำนวนเต็ม 32 บิต
auto
. auto const flags = std::numeric_limit<unsigned>::max()
.
unsigned int flags = -1; // all bits are true
"นี่เป็น [,] วิธีพกพาที่ดีในการทำให้สำเร็จหรือไม่"
พกพา? ครับ .
ดี? เป็นที่ถกเถียงกันโดยเห็นได้จากความสับสนทั้งหมดที่แสดงในหัวข้อนี้ การมีความชัดเจนเพียงพอที่เพื่อนโปรแกรมเมอร์ของคุณจะสามารถเข้าใจโค้ดได้โดยไม่สับสนควรเป็นหนึ่งในมิติที่เราวัดผลสำหรับโค้ดที่ดี
นอกจากนี้วิธีการนี้มีแนวโน้มที่จะมีคำเตือนคอมไพเลอร์ หากต้องการยกเลิกคำเตือนโดยไม่ทำให้คอมไพเลอร์ของคุณเสียคุณจะต้องมีการแคสต์ที่ชัดเจน ตัวอย่างเช่น,
unsigned int flags = static_cast<unsigned int>(-1);
นักแสดงที่ชัดเจนต้องการให้คุณใส่ใจกับประเภทเป้าหมาย หากคุณให้ความสนใจกับประเภทเป้าหมายคุณจะหลีกเลี่ยงข้อผิดพลาดของแนวทางอื่น ๆ
คำแนะนำของฉันคือให้ความสนใจกับประเภทเป้าหมายและตรวจสอบให้แน่ใจว่าไม่มีการแปลงโดยนัย ตัวอย่างเช่น:
unsigned int flags1 = UINT_MAX;
unsigned int flags2 = ~static_cast<unsigned int>(0);
unsigned long flags3 = ULONG_MAX;
unsigned long flags4 = ~static_cast<unsigned long>(0);
ซึ่งทั้งหมดนี้ถูกต้องและชัดเจนมากขึ้นสำหรับเพื่อนโปรแกรมเมอร์ของคุณ
และด้วย C ++ 11 : เราสามารถใช้auto
เพื่อทำให้สิ่งเหล่านี้ง่ายขึ้น:
auto flags1 = UINT_MAX;
auto flags2 = ~static_cast<unsigned int>(0);
auto flags3 = ULONG_MAX;
auto flags4 = ~static_cast<unsigned long>(0);
ฉันคิดว่าถูกต้องและชัดเจนดีกว่าถูกต้อง
การแปลง -1 เป็นประเภทที่ไม่ได้ลงชื่อรับรองโดยมาตรฐานเพื่อให้ได้ผลลัพธ์ทั้งหมด ใช้~0U
ไม่ดีโดยทั่วไปตั้งแต่0
มีประเภทและจะไม่กรอกบิตทั้งหมดของประเภทที่ไม่ได้ลงชื่อขนาดใหญ่เว้นแต่สิ่งที่คุณเขียนอย่างชัดเจนเช่นunsigned int
~0ULL
ในระบบที่มีสติ~0
ควรจะเหมือนกัน-1
แต่เนื่องจากมาตรฐานอนุญาตให้ใช้แทนตัวเสริมและสัญลักษณ์ / ขนาดได้ดังนั้นจึงไม่สามารถพกพาได้
แน่นอนว่าการเขียนออกมาเป็นเรื่องปกติ0xffffffff
หากคุณรู้ว่าคุณต้องการ 32 บิต แต่ -1 มีข้อได้เปรียบที่จะใช้งานได้ในบริบทใด ๆ แม้ว่าคุณจะไม่ทราบขนาดของประเภทก็ตามเช่นมาโครที่ทำงานได้หลายประเภท หรือหากขนาดของประเภทแตกต่างกันไปตามการใช้งาน ถ้าคุณทำทราบชนิดอีกวิธีที่ปลอดภัยที่จะได้รับทุกคนที่เป็นแมโครขีด จำกัดUINT_MAX
, ULONG_MAX
, ULLONG_MAX
ฯลฯ
โดยส่วนตัวฉันมักจะใช้ -1 มันใช้งานได้เสมอและคุณไม่ต้องคิดถึงมัน
~(type)0
( type
แน่นอนว่าต้องกรอกด้านขวา) การแคสต์ศูนย์ยังคงให้ผลลัพธ์เป็นศูนย์ดังนั้นจึงชัดเจนและการลบบิตทั้งหมดในประเภทเป้าหมายนั้นมีการกำหนดไว้อย่างชัดเจน ไม่บ่อยนักที่ฉันต้องการการดำเนินการนั้นจริงๆ YMMV.
neg
คำสั่ง เครื่องจักรที่มีพฤติกรรมการคำนวณทางคณิตศาสตร์ที่ลงนามปลอมจะมีรหัส opcodes เลขคณิตที่ลงชื่อ / ไม่ได้ลงนามแยกกัน แน่นอนว่าคอมไพเลอร์ที่ดีจริงๆมักจะเพิกเฉยต่อ opcodes ที่ลงชื่อไว้เสมอแม้กระทั่งสำหรับค่าที่ลงชื่อแล้วและด้วยเหตุนี้จึงได้รับ twos-complement ฟรี
var = ~(0*var)
กรณีที่จะล้มเหลวสำหรับการเป็นแคบชนิดที่ไม่ได้ลงชื่อกว่าvar
int
บางทีvar = ~(0U*var)
? (โดยส่วนตัวฉันยังชอบ-1
มากกว่า)
ตราบใดที่คุณมี#include <limits.h>
หนึ่งในไฟล์รวมของคุณคุณควรใช้
unsigned int flags = UINT_MAX;
หากคุณต้องการบิตที่มีมูลค่ายาวคุณสามารถใช้
unsigned long flags = ULONG_MAX;
ค่าเหล่านี้รับประกันได้ว่าจะมีการกำหนดบิตค่าทั้งหมดของผลลัพธ์เป็น 1 ไม่ว่าจะใช้เลขจำนวนเต็มที่เซ็นชื่ออย่างไร
ใช่. ตามที่กล่าวไว้ในคำตอบอื่น ๆ-1
เป็นแบบพกพามากที่สุด อย่างไรก็ตามมันไม่ได้มีความหมายมากนัก
ในการแก้ปัญหาเหล่านี้ลองใช้ตัวช่วยง่ายๆนี้:
static const struct All1s
{
template<typename UnsignedType>
inline operator UnsignedType(void) const
{
static_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");
return static_cast<UnsignedType>(-1);
}
} ALL_BITS_TRUE;
การใช้งาน:
unsigned a = ALL_BITS_TRUE;
uint8_t b = ALL_BITS_TRUE;
uint16_t c = ALL_BITS_TRUE;
uint32_t d = ALL_BITS_TRUE;
uint64_t e = ALL_BITS_TRUE;
ALL_BITS_TRUE ^ a
ที่a
เป็นจำนวนเต็มลงนาม? ประเภทยังคงเป็นเลขจำนวนเต็มและรูปแบบบิต (การแสดงวัตถุ) ขึ้นอยู่กับเป้าหมายว่าเป็นส่วนเสริมของ 2 หรือไม่
ALL_BITS_TRUE ^ a
ให้ข้อผิดพลาดในการคอมไพล์เนื่องจากALL_BITS_TRUE
ไม่ชัดเจน สามารถใช้งานได้เช่นuint32_t(ALL_BITS_TRUE) ^ a
ไร คุณสามารถลองด้วยตัวคุณเองในcpp.sh :) ปัจจุบันฉันต้องการเพิ่มstatic_assert(std::is_unsigned<UnsignedType>::value, "This is designed only for unsigned types");
ในเพื่อให้แน่ใจว่าผู้ใช้ไม่ได้พยายามที่จะใช้operator
int(ALL_BITS_TRUE)
ฉันจะอัปเดตคำตอบ
ฉันจะไม่ทำสิ่งที่ -1 มันค่อนข้างไม่ใช้งานง่าย (อย่างน้อยสำหรับฉัน) การกำหนดข้อมูลที่เซ็นชื่อให้กับตัวแปรที่ไม่ได้ลงชื่อดูเหมือนจะเป็นการละเมิดลำดับตามธรรมชาติของสิ่งต่างๆ
0xFFFF
ในสถานการณ์ของคุณฉันมักจะใช้ (ใช้ Fs ให้ถูกต้องสำหรับขนาดตัวแปร)
[BTW ฉันไม่ค่อยเห็นการหลอก -1 ในโค้ดจริง]
นอกจากนี้หากคุณจริงๆดูแลเกี่ยวกับแต่ละบิตใน vairable มันจะเป็นความคิดที่ดีที่จะเริ่มใช้ความกว้างคงที่uint8_t
, uint16_t
, uint32_t
ประเภท
บนโปรเซสเซอร์ IA-32 ของ Intel สามารถเขียน 0xFFFFFFFF ลงในรีจิสเตอร์ 64 บิตและได้ผลลัพธ์ที่คาดหวัง เนื่องจาก IA32e (ส่วนขยาย 64 บิตไปยัง IA32) รองรับเฉพาะ 32 บิตทันที ในคำแนะนำ 64 บิตทันที 32 บิตจะขยายการลงชื่อเป็น 64 บิต
สิ่งต่อไปนี้ผิดกฎหมาย:
mov rax, 0ffffffffffffffffh
ต่อไปนี้ทำให้ 64 1s ใน RAX:
mov rax, 0ffffffffh
เพื่อความสมบูรณ์ข้อมูลต่อไปนี้ใส่ 32 1 ในส่วนล่างของ RAX (aka EAX):
mov eax, 0ffffffffh
และอันที่จริงฉันเคยมีโปรแกรมล้มเหลวเมื่อฉันต้องการเขียน 0xffffffff ไปยังตัวแปร 64 บิตและฉันได้รับ 0xffffffffffffffffff แทน ใน C นี่จะเป็น:
uint64_t x;
x = UINT64_C(0xffffffff)
printf("x is %"PRIx64"\n", x);
ผลลัพธ์คือ:
x is 0xffffffffffffffff
ฉันคิดว่าจะโพสต์สิ่งนี้เป็นความคิดเห็นสำหรับคำตอบทั้งหมดที่บอกว่า 0xFFFFFFFF ถือว่า 32 บิต แต่หลายคนตอบว่าฉันคิดว่าฉันจะเพิ่มเป็นคำตอบแยกต่างหาก
UINT64_C(0xffffffff)
ขยายไปยังสิ่งที่ต้องการ0xffffffffuLL
เป็นบั๊กของคอมไพเลอร์ มาตรฐาน C กล่าวถึงค่าเป็นส่วนใหญ่ค่าที่แสดง0xffffffff
คือ 4294967295 (ไม่ใช่ 36893488147419103231) และไม่มีการแปลงประเภทจำนวนเต็มที่มีการเซ็นชื่อในสายตา
ดูคำตอบของ litb สำหรับคำอธิบายที่ชัดเจนเกี่ยวกับปัญหา
ความไม่เห็นด้วยของฉันคือพูดอย่างเคร่งครัดไม่มีหลักประกันสำหรับทั้งสองกรณี ฉันไม่รู้สถาปัตยกรรมใด ๆ ที่ไม่ได้แสดงถึงค่าที่ไม่ได้ลงนามของ 'หนึ่งน้อยกว่าสองยกกำลังของจำนวนบิต' ตามที่บิตทั้งหมดกำหนดไว้ แต่นี่คือสิ่งที่มาตรฐานกล่าวไว้จริง ๆ (3.9.1 / 7 บวก หมายเหตุ 44):
การแสดงประเภทอินทิกรัลต้องกำหนดค่าโดยใช้ระบบเลขฐานสองบริสุทธิ์ [หมายเหตุ 44:] การแสดงตำแหน่งสำหรับจำนวนเต็มที่ใช้เลขฐานสอง 0 และ 1 ซึ่งค่าที่แทนด้วยบิตต่อเนื่องเป็นส่วนเสริมเริ่มต้นด้วย 1 และคูณด้วยกำลังอินทิกรัลที่ต่อเนื่องกันของ 2 ยกเว้นบิตที่มี ตำแหน่งสูงสุด
นั่นทำให้ความเป็นไปได้ที่หนึ่งในบิตจะเป็นอะไรก็ได้
แม้ว่า0xFFFF
(หรือ0xFFFFFFFF
ฯลฯ ) อาจอ่านง่ายกว่า แต่ก็สามารถทำลายความสามารถในการพกพาในรหัสซึ่งจะพกพาได้ ตัวอย่างเช่นพิจารณารูทีนไลบรารีเพื่อนับจำนวนรายการในโครงสร้างข้อมูลที่มีการตั้งค่าบิตไว้ (บิตที่ถูกระบุโดยผู้เรียก) รูทีนอาจไม่เชื่อเรื่องพระเจ้าโดยสิ้นเชิงกับสิ่งที่บิตเป็นตัวแทน แต่ยังคงต้องมีค่าคงที่ "all bits set" ในกรณีเช่นนี้ -1 จะดีกว่าค่าคงที่ฐานสิบหกอย่างมากเนื่องจากจะใช้ได้กับขนาดบิตใด ๆ
ความเป็นไปได้อื่น ๆ หากใช้typedef
ค่าสำหรับ bitmask จะใช้ ~ (bitMaskType) 0; ถ้า bitmask เกิดขึ้นเป็นเพียงชนิด 16 บิตการแสดงออกว่าจะมี 16 บิตตั้ง (แม้ว่า 'int' มิฉะนั้นจะ 32 บิต) แต่ตั้งแต่ 16 บิตจะเป็นสิ่งที่จำเป็นต้องมีสิ่งที่ควรได้รับการปรับให้ไว้ที่หนึ่ง ใช้ประเภทที่เหมาะสมในตัวพิมพ์
อนึ่งนิพจน์ของแบบฟอร์มlongvar &= ~[hex_constant]
มี gotcha ที่น่ารังเกียจหากค่าคงที่ฐานสิบหกมีขนาดใหญ่เกินไปที่จะใส่ใน an int
แต่จะพอดีกับunsigned int
. ถ้าint
เป็น 16 บิตแล้วlongvar &= ~0x4000;
หรือlongvar &= ~0x10000
; จะล้างหนึ่งบิตlongvar
แต่longvar &= ~0x8000;
จะล้างบิต 15 และบิตทั้งหมดที่อยู่เหนือนั้น ค่าที่พอดีint
จะมีตัวดำเนินการส่วนเสริมนำไปใช้กับประเภทint
แต่ผลลัพธ์จะถูกขยายไปยังlong
การตั้งค่าบิตด้านบน ค่าที่มีขนาดใหญ่เกินไปสำหรับจะมีผู้ประกอบการที่สมบูรณ์นำไปใช้กับประเภทunsigned int
long
อย่างไรก็ตามค่าที่อยู่ระหว่างขนาดเหล่านั้นจะใช้ตัวดำเนินการส่วนเสริมในการพิมพ์unsigned int
ซึ่งจะถูกแปลงเป็นประเภทlong
โดยไม่มีส่วนขยายเครื่องหมาย
ในทางปฏิบัติ: ใช่
ในทางทฤษฎี: ไม่
-1 = 0xFFFFFFFF (หรือขนาดใดก็ตามที่ int อยู่บนแพลตฟอร์มของคุณ) เป็นจริงเฉพาะกับเลขคณิตเสริมสองตัว ในทางปฏิบัติมันจะใช้งานได้ แต่มีเครื่องดั้งเดิมอยู่ที่นั่น (เมนเฟรมของ IBM ฯลฯ ) ที่คุณมีบิตเซ็นจริงแทนที่จะเป็นตัวแทนเสริมของสอง โซลูชัน ~ 0 ที่คุณเสนอควรใช้ได้ทุกที่
ดังที่คนอื่น ๆ กล่าวไว้ -1 เป็นวิธีที่ถูกต้องในการสร้างจำนวนเต็มซึ่งจะแปลงเป็นชนิดที่ไม่ได้ลงชื่อโดยตั้งค่าบิตทั้งหมดเป็น 1 อย่างไรก็ตามสิ่งที่สำคัญที่สุดใน C ++ คือการใช้ประเภทที่ถูกต้อง ดังนั้นคำตอบที่ถูกต้องสำหรับปัญหาของคุณ (ซึ่งรวมถึงคำตอบสำหรับคำถามที่คุณถาม) คือ:
std::bitset<32> const flags(-1);
สิ่งนี้จะประกอบด้วยจำนวนบิตที่คุณต้องการเสมอ สร้าง a std::bitset
โดยตั้งค่าบิตทั้งหมดเป็น 1 ด้วยเหตุผลเดียวกันกับที่กล่าวถึงในคำตอบอื่น ๆ
มันปลอดภัยอย่างแน่นอนเนื่องจาก -1 จะมีการตั้งค่าบิตทั้งหมดไว้เสมอ แต่ฉันชอบ ~ 0 ดีกว่า -1 ไม่สมเหตุสมผลสำหรับunsigned int
ไฟล์. 0xFF
... ไม่ดีเพราะขึ้นอยู่กับความกว้างของชนิด
ฉันพูด:
int x;
memset(&x, 0xFF, sizeof(int));
สิ่งนี้จะให้ผลลัพธ์ที่ต้องการเสมอ
การใช้ประโยชน์จากข้อเท็จจริงที่ว่าการกำหนดบิตทั้งหมดให้เป็นหนึ่งสำหรับชนิดที่ไม่ได้ลงนามนั้นเทียบเท่ากับการรับค่าสูงสุดที่เป็นไปได้สำหรับประเภทที่กำหนด
และขยายขอบเขตของคำถามไปยังประเภทจำนวนเต็มที่ไม่ได้ลงชื่อทั้งหมด:
การกำหนด -1 ใช้ได้กับประเภทจำนวนเต็มที่ไม่ได้ลงชื่อ (int ไม่ได้ลงชื่อ, uint8_t, uint16_t ฯลฯ ) สำหรับทั้ง C และ C ++
อีกทางเลือกหนึ่งสำหรับ C ++ คุณสามารถ:
<limits>
และใช้std::numeric_limits< your_type >::max()
จุดประสงค์อาจเพิ่มความชัดเจนมากขึ้นเนื่องจากการมอบหมาย-1
จะต้องมีความคิดเห็นที่อธิบายได้เสมอ
วิธีที่จะทำให้ความหมายชัดเจนขึ้นและยังหลีกเลี่ยงการพิมพ์ซ้ำ:
const auto flags = static_cast<unsigned int>(-1);
ใช่การแสดงที่แสดงนั้นถูกต้องมากราวกับว่าเราทำในอีกทางหนึ่งคุณจะต้องใช้ตัวดำเนินการเพื่อย้อนกลับบิตทั้งหมด แต่ในกรณีนี้ตรรกะค่อนข้างตรงไปตรงมาหากเราพิจารณาขนาดของจำนวนเต็มในเครื่อง
ตัวอย่างเช่นในเครื่องส่วนใหญ่จำนวนเต็มคือ 2 ไบต์ = 16 บิตค่าสูงสุดที่สามารถเก็บได้คือ 2 ^ 16-1 = 65535 2 ^ 16 = 65536
0% 65536 = 0 -1% 65536 = 65535 ซึ่งตอบสนองต่อ 1111 ............. 1 และบิตทั้งหมดถูกตั้งค่าเป็น 1 (ถ้าเราพิจารณาคลาสตกค้าง mod 65536) ดังนั้นจึงมีมาก ตรงไปตรงมา
ฉันคิดว่า
ไม่ถ้าคุณคิดว่าแนวคิดนี้เป็นอาหารที่สมบูรณ์แบบสำหรับ ints ที่ไม่ได้ลงนามและใช้งานได้จริง
เพียงตรวจสอบส่วนของโปรแกรมต่อไปนี้
int หลัก () {
unsigned int a=2;
cout<<(unsigned int)pow(double(a),double(sizeof(a)*8));
unsigned int b=-1;
cout<<"\n"<<b;
getchar();
return 0;
}
คำตอบสำหรับ b = 4294967295 whcih คือ -1% 2 ^ 32 สำหรับจำนวนเต็ม 4 ไบต์
ดังนั้นจึงถูกต้องสมบูรณ์สำหรับจำนวนเต็มที่ไม่ได้ลงนาม
ในกรณีที่มีความคลาดเคลื่อนโปรดรายงาน