คำถามติดแท็ก undefined-behavior

ผลลัพธ์ที่คาดเดาไม่ได้ของการคอมไพล์หรือเอ็กซีคิ้วท์โปรแกรมที่ทำลายกฏของภาษาไม่ว่าจะเป็นคอมไพเลอร์, ล่ามหรือระบบรันไทม์จะต้องบังคับใช้ ห้ามใช้แท็กนี้สำหรับคำถามเกี่ยวกับประเภทข้อมูลหรือค่าส่งคืนของ "undefined" ในกรณีเหล่านั้นควรใช้แท็ก [ไม่ได้กำหนด] แทน

5
การเข้าถึงสมาชิกสหภาพที่ไม่ได้ใช้งานและพฤติกรรมที่ไม่ได้กำหนด?
ฉันรู้สึกว่าการเข้าถึงไฟล์ unionสมาชิกนอกเหนือจากชุดสุดท้ายคือ UB แต่ดูเหมือนว่าฉันจะไม่พบข้อมูลอ้างอิงที่มั่นคง (นอกเหนือจากคำตอบที่อ้างว่าเป็น UB แต่ไม่ได้รับการสนับสนุนจากมาตรฐาน) ดังนั้นพฤติกรรมที่ไม่ได้กำหนดหรือไม่?

2
เมื่อใดที่การเรียกใช้ฟังก์ชันสมาชิกบนอินสแตนซ์ว่างจะทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด
พิจารณารหัสต่อไปนี้: #include <iostream> struct foo { // (a): void bar() { std::cout << "gman was here" << std::endl; } // (b): void baz() { x = 5; } int x; }; int main() { foo* f = 0; f->bar(); // (a) f->baz(); // (b) } เราคาดว่า(b)จะขัดข้องเนื่องจากไม่มีสมาชิกที่เกี่ยวข้องxสำหรับตัวชี้ค่าว่าง ในทางปฏิบัติ(a)ไม่ผิดพลาดเนื่องจากthisไม่เคยใช้ตัวชี้ เนื่องจาก(b)dereferences thisตัวชี้ ( …

9
ฉันได้รับค่าที่มีขนาดใหญ่กว่า 8 บิตจากจำนวนเต็ม 8 บิตได้อย่างไร
ฉันติดตามแมลงที่น่ารังเกียจอย่างยิ่งที่ซ่อนอยู่หลังอัญมณีชิ้นเล็ก ๆ นี้ ผมทราบว่าต่อซี ++ สเปคลงนามล้นเป็นพฤติกรรมที่ไม่ได้กำหนด sizeof(int)แต่เมื่อล้นเกิดขึ้นเมื่อค่าที่จะขยายไปยังบิตกว้าง ตามที่ผมเข้าใจมัน incrementing ไม่ควรที่เคยเป็นพฤติกรรมที่ไม่ได้กำหนดตราบเท่าที่char sizeof(char) < sizeof(int)แต่นั่นไม่ได้อธิบายว่าcการได้รับค่าที่เป็นไปไม่ได้อย่างไร ในฐานะจำนวนเต็ม 8 บิตจะcเก็บค่าที่มากกว่าความกว้างบิตได้อย่างไร รหัส // Compiled with gcc-4.7.2 #include <cstdio> #include <stdint.h> #include <climits> int main() { int8_t c = 0; printf("SCHAR_MIN: %i\n", SCHAR_MIN); printf("SCHAR_MAX: %i\n", SCHAR_MAX); for (int32_t i = 0; i <= 300; i++) printf("c: …

8
พฤติกรรมที่ไม่ได้กำหนดทางเทคนิคของ "แฮ็กโครงสร้าง" หรือไม่
สิ่งที่ฉันกำลังถามคือเคล็ดลับ "สมาชิกคนสุดท้ายของโครงสร้างมีความยาวผันแปร" ที่รู้จักกันดี มันจะเป็นดังนี้: struct T { int len; char s[1]; }; struct T *p = malloc(sizeof(struct T) + 100); p->len = 100; strcpy(p->s, "hello world"); เนื่องจากวิธีการจัดวางโครงสร้างในหน่วยความจำเราจึงสามารถซ้อนโครงสร้างบนบล็อกที่ใหญ่กว่าที่จำเป็นและปฏิบัติต่อสมาชิกตัวสุดท้ายราวกับว่ามันมีขนาดใหญ่กว่าที่1 charระบุ คำถามคือเทคนิคนี้เป็นพฤติกรรมที่ไม่ได้กำหนดทางเทคนิคหรือไม่? . ฉันคาดหวังว่าจะเป็นเช่นนั้น แต่ก็อยากรู้ว่ามาตรฐานพูดถึงเรื่องนี้อย่างไร PS: ฉันทราบถึงแนวทางของ C99 ในเรื่องนี้ฉันต้องการให้คำตอบยึดติดกับเวอร์ชันของเคล็ดลับตามที่ระบุไว้ด้านบนโดยเฉพาะ

2
กำลังใช้ malloc สำหรับพฤติกรรมที่ไม่ได้กำหนดไว้จนถึง C ++ 20
ฉันได้รับแจ้งว่ารหัสต่อไปนี้มีพฤติกรรมที่ไม่ได้กำหนดไว้จนถึง C ++ 20: int *p = (int*)malloc(sizeof(int)); *p = 10; เป็นเช่นนั้นจริงหรือ? อาร์กิวเมนต์คืออายุการใช้งานของintอ็อบเจ็กต์ไม่ได้เริ่มต้นก่อนกำหนดค่าให้กับมัน ( P0593R6 ) ในการแก้ไขปัญหาnewควรใช้ตำแหน่ง: int *p = (int*)malloc(sizeof(int)); new (p) int; *p = 10; เราต้องเรียกตัวสร้างเริ่มต้นที่ไม่สำคัญเพื่อเริ่มอายุการใช้งานของวัตถุหรือไม่? ในเวลาเดียวกันรหัสไม่มีพฤติกรรมที่ไม่ได้กำหนดใน C บริสุทธิ์ แต่จะเป็นอย่างไรถ้าฉันจัดสรรintรหัสใน C และใช้ในรหัส C ++? // C source code: int *alloc_int(void) { int *p = (int*)malloc(sizeof(int)); *p = 10; …

3
การพิมพ์พอยน์เตอร์ว่างด้วย% p เป็นพฤติกรรมที่ไม่ได้กำหนด?
เป็นพฤติกรรมที่ไม่ได้กำหนดไว้ในการพิมพ์พอยน์เตอร์ว่างด้วยตัว%pระบุการแปลงหรือไม่ #include <stdio.h> int main(void) { void *p = NULL; printf("%p", p); return 0; } คำถามนี้ใช้กับมาตรฐาน C ไม่ใช่กับการใช้งาน C

8
สาขาที่มีพฤติกรรมที่ไม่ได้กำหนดสามารถถือว่าไม่สามารถเข้าถึงได้และปรับให้เหมาะสมเป็นรหัสตายได้หรือไม่
พิจารณาข้อความต่อไปนี้: *((char*)NULL) = 0; //undefined behavior มันก่อให้เกิดพฤติกรรมที่ไม่ได้กำหนดไว้อย่างชัดเจน การมีอยู่ของคำสั่งดังกล่าวในโปรแกรมที่กำหนดหมายความว่าโปรแกรมทั้งหมดไม่ได้กำหนดไว้หรือพฤติกรรมนั้นจะไม่ได้กำหนดก็ต่อเมื่อโฟลว์การควบคุมมาถึงคำสั่งนี้ โปรแกรมต่อไปนี้จะถูกกำหนดไว้อย่างดีในกรณีที่ผู้ใช้ไม่เคยป้อนหมายเลข3หรือไม่? while (true) { int num = ReadNumberFromConsole(); if (num == 3) *((char*)NULL) = 0; //undefined behavior } หรือเป็นพฤติกรรมที่ไม่ได้กำหนดโดยสิ้นเชิงไม่ว่าผู้ใช้จะเข้ามา? นอกจากนี้คอมไพเลอร์สามารถสันนิษฐานได้ว่าพฤติกรรมที่ไม่ได้กำหนดจะไม่ถูกดำเนินการในรันไทม์? ซึ่งจะช่วยให้สามารถใช้เหตุผลย้อนหลังได้: int num = ReadNumberFromConsole(); if (num == 3) { PrintToConsole(num); *((char*)NULL) = 0; //undefined behavior } ที่นี่คอมไพเลอร์อาจให้เหตุผลว่าในกรณีที่num == 3เรามักจะเรียกใช้พฤติกรรมที่ไม่ได้กำหนด ดังนั้นกรณีนี้จะต้องเป็นไปไม่ได้และไม่จำเป็นต้องพิมพ์หมายเลข ifคำสั่งทั้งหมดสามารถปรับให้เหมาะสมได้ …

10
ทำไม printf (“% f”, 0); ให้พฤติกรรมที่ไม่ได้กำหนด?
คำสั่ง printf("%f\n",0.0f); พิมพ์ 0. อย่างไรก็ตามคำสั่ง printf("%f\n",0); พิมพ์ค่าสุ่ม ฉันรู้ว่าฉันกำลังแสดงพฤติกรรมบางอย่างที่ไม่ได้กำหนด แต่ฉันไม่สามารถหาสาเหตุได้โดยเฉพาะ ค่าทศนิยมที่บิตทั้งหมดเป็น 0 ยังคงใช้ได้floatโดยมีค่าเป็น 0 floatและintมีขนาดเท่ากันบนเครื่องของฉัน (หากเกี่ยวข้องกัน) เหตุใดการใช้ลิเทอรัลจำนวนเต็มแทนที่จะเป็นลิเทอรัลจุดลอยตัวจึงprintfทำให้เกิดพฤติกรรมนี้ ปล. พฤติกรรมเดียวกันนี้สามารถมองเห็นได้ถ้าฉันใช้ int i = 0; printf("%f\n", i);

12
จุดใดในลูปที่ทำให้จำนวนเต็มล้นกลายเป็นพฤติกรรมที่ไม่ได้กำหนด
นี่เป็นตัวอย่างเพื่ออธิบายคำถามของฉันซึ่งเกี่ยวข้องกับโค้ดที่ซับซ้อนกว่านี้ซึ่งฉันไม่สามารถโพสต์ได้ที่นี่ #include <stdio.h> int main() { int a = 0; for (int i = 0; i < 3; i++) { printf("Hello\n"); a = a + 1000000000; } } โปรแกรมนี้มีพฤติกรรมที่ไม่ได้กำหนดบนแพลตฟอร์มของฉันเพราะaจะล้นในลูปที่ 3 นั่นทำให้โปรแกรมทั้งหมดมีพฤติกรรมที่ไม่ได้กำหนดไว้หรือหลังจากเกิดเหตุการณ์ล้นขึ้นจริงหรือไม่? คอมไพเลอร์สามารถทำงานได้หรือไม่ที่a จะล้นออกมาเพื่อให้สามารถประกาศลูปทั้งหมดโดยไม่ได้กำหนดและไม่ต้องกังวลกับการรัน printfs แม้ว่าทั้งหมดจะเกิดขึ้นก่อนที่จะล้น (ติดแท็ก C และ C ++ แม้ว่าจะแตกต่างกันเพราะฉันสนใจคำตอบสำหรับทั้งสองภาษาหากแตกต่างกัน)

4
มันถูกกฎหมายหรือไม่สำหรับซอร์สโค้ดที่มีพฤติกรรมที่ไม่ได้กำหนดเพื่อทำให้คอมไพลเลอร์พัง?
สมมติว่าฉันไปรวบรวมซอร์สโค้ด C ++ ที่เขียนไม่ดีซึ่งเรียกใช้พฤติกรรมที่ไม่ได้กำหนดดังนั้น (ตามที่พวกเขาพูด) "อะไรก็เกิดขึ้นได้" จากมุมมองของข้อกำหนดภาษา C ++ ที่เห็นว่ายอมรับได้ในคอมไพเลอร์ "conformant" ทำ "อะไรก็ได้" ในสถานการณ์นี้รวมถึงคอมไพเลอร์ที่ขัดข้อง (หรือขโมยรหัสผ่านของฉันหรือทำงานผิดพลาดหรือเกิดข้อผิดพลาดในเวลาคอมไพล์) หรือเป็น ขอบเขตของพฤติกรรมที่ไม่ได้กำหนด จำกัด เฉพาะสิ่งที่สามารถเกิดขึ้นได้เมื่อเรียกใช้งานผลลัพธ์

5
โหลดพฤติกรรมที่ไม่ได้กำหนดและจุดลำดับใหม่
พิจารณาหัวข้อนี้เป็นภาคต่อของหัวข้อต่อไปนี้: งวดก่อนหน้า พฤติกรรมที่ไม่ได้กำหนดและจุดลำดับ มาทบทวนสำนวนที่ตลกและซับซ้อนนี้กันอีกครั้ง(วลีตัวเอียงนำมาจากหัวข้อด้านบน * smile *): i += ++i; เรากล่าวว่าสิ่งนี้ก่อให้เกิดพฤติกรรมที่ไม่ได้กำหนด ผมเข้าใจว่าเมื่อพูดแบบนี้เราคิดว่าโดยปริยายประเภทของการiเป็นหนึ่งในตัวชนิด เกิดอะไรขึ้นถ้าประเภทของการiเป็นผู้ใช้กำหนดชนิดใด? บอกว่าประเภทของมันคือIndexสิ่งที่กำหนดไว้ในโพสต์นี้ (ดูด้านล่าง) มันจะยังคงเรียกใช้พฤติกรรมที่ไม่ได้กำหนดหรือไม่? ถ้าใช่เพราะเหตุใด มันไม่เทียบเท่ากับการเขียนi.operator+=(i.operator++());หรือแม้แต่ไวยากรณ์ที่เรียบง่ายกว่า i.add(i.inc());? หรือพวกเขาเรียกร้องพฤติกรรมที่ไม่ได้กำหนดมากเกินไป? ถ้าไม่ทำไมไม่? ท้ายที่สุดวัตถุiจะถูกแก้ไขสองครั้งระหว่างจุดลำดับที่ต่อเนื่องกัน โปรดระลึกถึงหลักการง่ายๆ: นิพจน์สามารถแก้ไขค่าของอ็อบเจ็กต์ได้เพียงครั้งเดียวระหว่าง "ลำดับจุด" ที่ต่อเนื่องกันและถ้า i += ++iเป็นนิพจน์ก็จะต้องเรียกใช้พฤติกรรมที่ไม่ได้กำหนดหากเป็นเช่นนั้นจะมีค่าเทียบเท่าi.operator+=(i.operator++());และ i.add(i.inc());ต้องเรียกใช้พฤติกรรมที่ไม่ได้กำหนดซึ่ง ดูเหมือนจะไม่จริง! (เท่าที่ฉันเข้าใจ) หรือi += ++iไม่ใช่นิพจน์ที่ขึ้นต้นด้วย? ถ้าเป็นเช่นนั้นคำจำกัดความของนิพจน์คืออะไร? หากเป็นนิพจน์และในเวลาเดียวกันพฤติกรรมของมันก็ถูกกำหนดไว้อย่างดีเช่นกันแสดงว่าจำนวนจุดลำดับที่เกี่ยวข้องกับนิพจน์นั้นขึ้นอยู่กับประเภทของตัวถูกดำเนินการที่เกี่ยวข้องกับนิพจน์ ฉันถูกต้อง (แม้บางส่วน) หรือไม่? แล้วสำนวนนี้ล่ะ? //Consider two cases: //1. If a is an array …

10
โอเวอร์โฟลว์ที่มีการลงชื่อใน C ++ และพฤติกรรมที่ไม่ได้กำหนด (UB)
ฉันสงสัยเกี่ยวกับการใช้รหัสดังต่อไปนี้ int result = 0; int factor = 1; for (...) { result = ... factor *= 10; } return result; หากวนซ้ำซ้ำหลายnครั้งfactorจะถูกคูณด้วยจำนวนเวลาที่10แน่นอน nอย่างไรก็ตามfactorมีการใช้งานเฉพาะหลังจากที่ถูกคูณด้วย10จำนวนn-1ครั้งทั้งหมด หากเราสมมติว่าfactorไม่มีการโอเวอร์โฟลว์ยกเว้นในการวนซ้ำครั้งสุดท้ายของลูป แต่อาจโอเวอร์โฟลว์ในการวนซ้ำครั้งสุดท้ายของลูปรหัสนั้นควรยอมรับได้หรือไม่ ในกรณีนี้ค่าของfactorจะไม่ถูกใช้อย่างแน่นอนหลังจากเกิดการล้น ฉันกำลังถกเถียงกันว่าควรยอมรับรหัสเช่นนี้หรือไม่ มันจะเป็นไปได้ที่จะนำการคูณเข้ามาในคำสั่ง if และเพียงแค่ไม่ทำการคูณในการวนซ้ำครั้งสุดท้ายของลูปเมื่อมันสามารถล้น ข้อเสียคือมัน clutters รหัสและเพิ่มสาขาที่ไม่จำเป็นที่จะต้องตรวจสอบในการวนซ้ำก่อนหน้านี้ทั้งหมด ฉันยังสามารถวนซ้ำวนซ้ำในเวลาที่น้อยลงและทำซ้ำลูปบอดี้อีกครั้งหลังจากวนซ้ำอีกครั้งนี่ทำให้โค้ดซับซ้อน มีการใช้รหัสจริงในวงในที่แน่นหนาซึ่งใช้เวลาในการประมวลผลของ CPU ทั้งหมดในแอปพลิเคชันกราฟิกแบบเรียลไทม์

3
การเพิ่มตัวชี้ไปยังอาร์เรย์ไดนามิกขนาด 0 ไม่ได้กำหนดไว้หรือไม่
AFAIK แม้ว่าเราจะไม่สามารถสร้างอาร์เรย์หน่วยความจำคงที่ขนาด 0 แต่เราสามารถทำได้ด้วยไดนามิก: int a[0]{}; // Compile-time error int* p = new int[0]; // Is well-defined อย่างที่ฉันได้อ่านpทำหน้าที่เหมือนองค์ประกอบสุดท้ายที่จบแล้ว ฉันสามารถพิมพ์ที่อยู่ที่pชี้ไปได้ if(p) cout << p << endl; แม้ว่าฉันจะแน่ใจว่าเราไม่สามารถอ้างถึงตัวชี้ (องค์ประกอบสุดท้ายที่ผ่านมา) เนื่องจากเราไม่สามารถใช้ตัววนซ้ำ (องค์ประกอบที่ผ่านมา) แต่สิ่งที่ฉันไม่แน่ใจคือการเพิ่มตัวชี้นั้นpหรือไม่ พฤติกรรมที่ไม่ได้กำหนด (UB) เหมือนกับตัววนซ้ำหรือไม่ p++; // UB?

7
การเปรียบเทียบตัวชี้ทำงานใน C อย่างไร การเปรียบเทียบพอยน์เตอร์ที่ไม่ได้ชี้ไปที่อาเรย์นั้นเป็นสิ่งที่ดีหรือไม่?
ใน K&R (ภาษาการเขียนโปรแกรม C รุ่นที่ 2) บทที่ 5 ฉันอ่านต่อไปนี้: ขั้นแรกให้เปรียบเทียบตัวชี้ภายใต้สถานการณ์บางอย่าง ถ้าpและqชี้ไปที่สมาชิกของอาร์เรย์เดียวกันแล้วความสัมพันธ์ที่ชอบ==, !=, <, >=ฯลฯ การทำงานอย่างถูกต้อง ซึ่งดูเหมือนว่าบ่งบอกว่ามีเพียงพอยน์เตอร์ที่ชี้ไปยังอาร์เรย์เดียวกันเท่านั้นที่สามารถเปรียบเทียบได้ อย่างไรก็ตามเมื่อฉันลองใช้รหัสนี้ char t = 't'; char *pt = &t; char x = 'x'; char *px = &x; printf("%d\n", pt > px); 1 ถูกพิมพ์ไปที่หน้าจอ ก่อนอื่นฉันคิดว่าฉันจะไม่ได้กำหนดหรือบางประเภทหรือข้อผิดพลาดเพราะptและpxไม่ได้ชี้ไปที่อาร์เรย์เดียวกัน (อย่างน้อยก็ในความเข้าใจของฉัน) เป็นpt > pxเพราะพอยน์เตอร์ทั้งสองชี้ไปที่ตัวแปรที่เก็บอยู่ในสแต็กและสแต็กโตขึ้นดังนั้นที่อยู่หน่วยความจำของtมากกว่าที่อยู่x? อะไรคือสาเหตุที่pt > pxแท้จริง ฉันสับสนมากขึ้นเมื่อนำ malloc เข้ามานอกจากนี้ใน …

2
พฤติกรรมแปลก ๆ กับฟิลด์คลาสเมื่อเพิ่มไปยัง std :: vector
ฉันได้พบพฤติกรรมแปลก ๆ บางอย่าง (บนเสียงดังกราวและ GCC) ในสถานการณ์ต่อไปนี้ ฉันมีเวกเตอร์ที่มีองค์ประกอบหนึ่งซึ่งเป็นตัวอย่างของการเรียนnodes Nodeจากนั้นฉันเรียกฟังก์ชันnodes[0]ที่เพิ่มNodeเวกเตอร์ใหม่ เมื่อเพิ่มโหนดใหม่ฟิลด์ของวัตถุที่เรียกจะถูกรีเซ็ต! อย่างไรก็ตามพวกเขาดูเหมือนจะกลับสู่ปกติอีกครั้งเมื่อฟังก์ชั่นเสร็จสิ้น ฉันเชื่อว่านี่เป็นตัวอย่างที่ทำซ้ำได้น้อยที่สุด: #include <iostream> #include <vector> using namespace std; struct Node; vector<Node> nodes; struct Node{ int X; void set(){ X = 3; cout << "Before, X = " << X << endl; nodes.push_back(Node()); cout << "After, X = " << X …

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.