เราสามารถมีพอยน์เตอร์ได้กี่ระดับ


443

จำนวนพอยน์เตอร์ ( *) ที่อนุญาตให้มีในตัวแปรเดียว

ลองพิจารณาตัวอย่างต่อไปนี้

int a = 10;
int *p = &a;

ในทำนองเดียวกันเราสามารถมี

int **q = &p;
int ***r = &q;

และอื่น ๆ

ตัวอย่างเช่น,

int ****************zz;

582
หากสิ่งนั้นกลายเป็นปัญหาที่แท้จริงสำหรับคุณคุณกำลังทำบางสิ่งผิดปกติ
ThiefMaster

279
คุณสามารถเพิ่มระดับของพอยน์เตอร์จนกว่าสมองของคุณจะระเบิดหรือคอมไพเลอร์ละลาย - ไม่ว่าจะเกิดอะไรขึ้นเร็วที่สุด
JeremyP

47
เนื่องจากพอยน์เตอร์ไปยังพอยน์เตอร์เป็นอีกครั้ง, เพียงแค่พอยน์เตอร์, จึงไม่ควรมีข้อ จำกัด ทางทฤษฎีใด ๆ บางทีคอมไพเลอร์จะไม่สามารถจัดการได้เกินขีด จำกัด ที่น่าขัน แต่ก็ดี ...
Christian Rau

73
ด้วย c ++ ใหม่ล่าสุดคุณควรใช้สิ่งที่ต้องการstd::shared_ptr<shared_ptr<shared_ptr<...shared_ptr<int>...>>>
josefx

44
@josefx - สิ่งนี้แสดงให้เห็นถึงปัญหาในมาตรฐาน C ++ - ไม่มีวิธีใดที่จะเพิ่มพอยน์เตอร์อัจฉริยะให้เป็นพลัง เราต้องเรียกร้องส่วนขยายทันทีเพื่อสนับสนุนเช่น(pow (std::shared_ptr, -0.3))<T> x;ระดับ -0.3 ทางอ้อม
Steve314

คำตอบ:


400

Cมาตรฐานระบุขีด จำกัด ล่าง:

5.2.4.1 ข้อ จำกัด การแปล

276 การดำเนินการจะสามารถแปลและดำเนินการอย่างน้อยหนึ่งโปรแกรมที่มีอย่างน้อยหนึ่งอินสแตนซ์ของหนึ่งในข้อ จำกัด ต่อไปนี้: [... ]

279 - 12 ตัวชี้อาร์เรย์และฟังก์ชันการประกาศ (ในการรวมกันใด ๆ ) การแก้ไขเลขคณิตโครงสร้างยูเนี่ยนหรือประเภทโมฆะในการประกาศ

ขีด จำกัด สูงสุดคือการใช้งานเฉพาะ


121
มาตรฐาน C ++ "แนะนำ" ที่สนับสนุนการใช้งานอย่างน้อย 256 (ความสามารถในการอ่านแนะนำให้คุณไม่เกิน 2 หรือ 3 และถึงตอนนั้น: มากกว่าหนึ่งควรจะยอดเยี่ยม)
James Kanze

22
ข้อ จำกัด นี้เป็นเรื่องเกี่ยวกับจำนวนในการประกาศเดียว; มันไม่ได้กำหนดขอบเขตบนวิธีร้ายมากที่คุณสามารถบรรลุผ่านหลายtypedefs
Kaz

11
@Kaz - ใช่นั่นเป็นเรื่องจริง แต่เนื่องจากสเป็คคือ (ไม่มีการเล่นสำนวนเจตนา) ระบุขีด จำกัด ล่างที่ได้รับคำสั่งมันเป็นขอบเขตที่มีประสิทธิภาพบนคอมไพเลอร์ตามมาตรฐานทั้งหมดที่จำเป็นในการสนับสนุน อาจต่ำกว่าขอบเขตบนเฉพาะของผู้ขายแน่นอน ปรับเปลี่ยนให้แตกต่างกัน (เพื่อจัดให้สอดคล้องกับคำถามของ OP) มันเป็นค่าสูงสุดที่ อนุญาตโดยสเป็ค (สิ่งอื่นจะเป็นเฉพาะผู้ขาย) บิตปิดแทนเจนต์โปรแกรมเมอร์ควร (อย่างน้อยในกรณีทั่วไป) ถือว่าเป็นของพวกเขา ขีด จำกัด บน (ยกเว้นว่าพวกเขามีเหตุผลที่ถูกต้องในการพึ่งพาขอบเขตเฉพาะของผู้ขาย) ... ฉันคิดว่า
luis.espinal

5
ในบันทึกอื่น ๆ ฉันจะเริ่มตัดตัวเองถ้าฉันต้องทำงานกับรหัสที่มีเครือข่ายการเลิกล้มยาว (โดยเฉพาะอย่างยิ่งเมื่อมีผู้คนมากมายทั่วทุกที่ )
luis.espinal

11
@beryllium: โดยปกติแล้วตัวเลขเหล่านี้มาจากการสำรวจซอฟต์แวร์มาตรฐานก่อน ในกรณีนี้สันนิษฐานว่าพวกเขาดูโปรแกรม C ทั่วไปและคอมไพเลอร์ C ที่มีอยู่และพบว่าคอมไพเลอร์อย่างน้อยหนึ่งตัวที่อาจมีปัญหากับมากกว่า 12 และ / หรือไม่มีโปรแกรมที่พังถ้าคุณ จำกัด ไว้ที่ 12

155

ที่จริงแล้วโปรแกรม C มักใช้ประโยชน์จากการบอกทางแบบไม่สิ้นสุด ระดับคงที่หนึ่งหรือสองระดับเป็นเรื่องปกติ สามทิศทางเป็นของหายาก แต่ไม่มีที่สิ้นสุดเป็นเรื่องธรรมดามาก

การชี้ทางอ้อมแบบไม่สิ้นสุดนั้นทำได้ด้วยความช่วยเหลือของ struct ไม่ใช่จากตัวประกาศโดยตรงซึ่งจะเป็นไปไม่ได้ และจำเป็นต้องมีโครงสร้างเพื่อให้คุณสามารถรวมข้อมูลอื่น ๆ ในโครงสร้างนี้ในระดับที่แตกต่างกันซึ่งสิ่งนี้สามารถยกเลิกได้

struct list { struct list *next; ... };

list->next->next->next->...->nextตอนนี้คุณสามารถมี นี่เป็นเพียงการชี้หลายทิศทาง: *(*(..(*(*(*list).next).next).next...).next).next. และ.nextมันก็เป็นเสียงรบกวนเมื่อมันเป็นสมาชิกคนแรกของโครงสร้างดังนั้นเราจึงสามารถจินตนาการได้ว่าเป็น***..***ptrเมื่อมันเป็นครั้งแรกที่สมาชิกของโครงสร้างเพื่อให้เราสามารถคิดนี้เป็น

ไม่มีข้อ จำกัด ใด ๆ ในเรื่องนี้เพราะการเชื่อมโยงสามารถข้ามผ่านวนซ้ำมากกว่าการแสดงออกแบบนี้และยิ่งกว่านั้นโครงสร้างสามารถทำให้เป็นวงกลมได้อย่างง่ายดาย

ดังนั้นในคำอื่น ๆ รายการที่เชื่อมโยงอาจเป็นตัวอย่างที่ดีที่สุดของการเพิ่มอีกระดับของการอ้อมในการแก้ปัญหาเนื่องจากคุณทำแบบไดนามิกกับการกดทุกครั้ง :)


48
แต่นั่นเป็นปัญหาที่แตกต่างอย่างสิ้นเชิง - โครงสร้างที่มีตัวชี้ไปยังโครงสร้างอื่นนั้นแตกต่างจากตัวชี้ตัวชี้มาก int ***** เป็นประเภทที่แตกต่างจาก int ****
ปุย

12
มันไม่ได้ "แตกต่าง" มากนัก ความแตกต่างคือปุย มันอยู่ใกล้กับไวยากรณ์มากกว่าความหมาย ตัวชี้ไปยังวัตถุตัวชี้หรือตัวชี้ไปยังวัตถุโครงสร้างซึ่งประกอบด้วยตัวชี้หรือไม่ มันเป็นสิ่งเดียวกัน การไปยังองค์ประกอบที่สิบของรายการคือระดับการกำหนดทิศทางทางอ้อมสิบระดับ (แน่นอนความสามารถในการแสดงโครงสร้างอนันต์ขึ้นอยู่กับชนิดของโครงสร้างที่สามารถชี้ไปที่ตัวเองผ่านประเภทโครงสร้างที่ไม่สมบูรณ์เพื่อให้list->nextและlist->next->nextเป็นประเภทเดียวกัน; มิฉะนั้นเราจะต้องสร้างประเภทไม่มีที่สิ้นสุด)
Kaz

34
ฉันไม่ได้สังเกตเห็นอย่างมีสติว่าชื่อของคุณปุยเมื่อฉันใช้คำว่า "ปุย" จิตใต้สำนึกมีอิทธิพลต่อ? แต่ฉันแน่ใจว่าฉันเคยใช้คำนี้มาก่อน
Kaz

3
โปรดจำไว้ว่าในภาษาเครื่องคุณสามารถทำซ้ำสิ่งที่ต้องการLOAD R1, [R1]ตราบใดที่ R1 เป็นตัวชี้ที่ถูกต้องในทุกขั้นตอน ไม่มีประเภทที่เกี่ยวข้องนอกจาก "คำที่มีที่อยู่" ไม่ว่าจะมีการประกาศประเภทหรือไม่ก็ไม่ได้กำหนดทิศทางและมีระดับกี่ระดับ
Kaz

4
ไม่ใช่ถ้าโครงสร้างเป็นแบบวงกลม หากR1เก็บที่อยู่ของสถานที่ซึ่งชี้ไปที่ตัวเองก็LOAD R1, [R1]สามารถดำเนินการในวงวนไม่สิ้นสุด
Kaz

83

ในทางทฤษฎี:

คุณสามารถมีทางอ้อมได้หลายระดับตามที่คุณต้องการ

จวน:

แน่นอนไม่มีสิ่งใดที่ใช้หน่วยความจำได้ไม่ จำกัด จะมีข้อ จำกัด เนื่องจากทรัพยากรที่มีในสภาพแวดล้อมโฮสต์ ดังนั้นในทางปฏิบัติจะมีข้อ จำกัด สูงสุดสำหรับสิ่งที่การใช้งานสามารถสนับสนุนและการนำไปปฏิบัตินั้นจะบันทึกไว้อย่างเหมาะสม ดังนั้นในสิ่งประดิษฐ์ทั้งหมดมาตรฐานไม่ได้ระบุขีด จำกัด สูงสุด แต่จะระบุขีด จำกัด ล่าง

นี่คือการอ้างอิง:

C99 มาตรฐาน 5.2.4.1 ข้อ จำกัด การแปล:

- 12 ตัวชี้อาร์เรย์และฟังก์ชันการประกาศ (ในชุดใด ๆ ) การแก้ไขเลขคณิตโครงสร้างยูเนี่ยนหรือประเภทโมฆะในการประกาศ

สิ่งนี้ระบุขีด จำกัด ล่างที่ทุกการใช้งานต้องสนับสนุน โปรดทราบว่าในเชิงอรรถมาตรฐานเพิ่มเติมพูดว่า:

18) การติดตั้งใช้งานควรหลีกเลี่ยงการกำหนดขีด จำกัด การแปลคงที่เมื่อทำได้


16
ทางอ้อมไม่ล้นกองใด ๆ !
Basile Starynkevitch

1
ถูกต้องฉันรู้สึกหงุดหงิดกับการอ่านและตอบคำถาม q เนื่องจากมีการ จำกัด พารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชัน ฉันไม่รู้ว่าทำไม!
Alok บันทึก

2
@basile - ฉันคาดว่า stack-depth จะเป็นปัญหาใน parser อัลกอริทึมการแยกวิเคราะห์อย่างเป็นทางการจำนวนมากมีสแต็กเป็นองค์ประกอบสำคัญ คอมไพเลอร์ C ++ ส่วนใหญ่อาจใช้ตัวแปรของการเรียกซ้ำแบบซ้ำ ๆ แต่ถึงแม้จะต้องอาศัยตัวประมวลผลสแต็ก การทำรังกฎไวยากรณ์ให้มากขึ้นหมายถึงสแต็คที่ลึกกว่า
Steve314

8
ทางอ้อมไม่ล้นกองใด ๆ ! -> ไม่! parser stack สามารถล้น สแต็คเกี่ยวข้องกับตัวชี้ทางอ้อมอย่างไร ตัวแยกวิเคราะห์สแต็ก!
Pavan Manjunath

หาก*โอเวอร์โหลดสำหรับจำนวนคลาสในแถวและแต่ละโอเวอร์โหลดส่งคืนออบเจ็กต์ประเภทอื่นในแถวดังนั้นอาจมีสแต็คโอเวอร์โฟลว์สำหรับการเรียกฟังก์ชันที่ถูกโยง
Nawaz

76

อย่างที่ผู้คนพูดกันไม่ จำกัด "ในทางทฤษฎี" อย่างไรก็ตามสิ่งที่น่าสนใจคือฉันรันสิ่งนี้ด้วย g ++ 4.1.2 และทำงานกับขนาดสูงสุด 20,000 การคอมไพล์ค่อนข้างช้า แต่ฉันไม่ได้ลองสูงกว่านี้ ดังนั้นฉันเดา g ++ ไม่ได้กำหนดขีด จำกัด ใด ๆ (ลองตั้งค่าsize = 10และค้นหาใน ptr.cpp หากไม่ชัดเจนทันที)

g++ create.cpp -o create ; ./create > ptr.cpp ; g++ ptr.cpp -o ptr ; ./ptr

create.cpp

#include <iostream>

int main()
{
    const int size = 200;
    std::cout << "#include <iostream>\n\n";
    std::cout << "int main()\n{\n";
    std::cout << "    int i0 = " << size << ";";
    for (int i = 1; i < size; ++i)
    {
        std::cout << "    int ";
        for (int j = 0; j < i; ++j) std::cout << "*";
        std::cout << " i" << i << " = &i" << i-1 << ";\n";
    }
    std::cout << "    std::cout << ";
    for (int i = 1; i < size; ++i) std::cout << "*";
    std::cout << "i" << size-1 << " << \"\\n\";\n";
    std::cout << "    return 0;\n}\n";
    return 0;
}

72
ฉันไม่สามารถรับมากกว่า 98242 เมื่อฉันลอง (ฉันทำสคริปต์ใน Python สองเท่าของจำนวน*จนกว่าฉันจะได้รับข้อความที่ล้มเหลวและสคริปต์ก่อนหน้านั้นที่ผ่านมาฉันได้ทำการค้นหาแบบไบนารีในช่วงเวลานั้นสำหรับครั้งแรกที่ล้มเหลวการทดสอบทั้งหมดใช้เวลาน้อยกว่าหนึ่งวินาที เรียกใช้)
James Kanze

63

ฟังดูสนุกดี

  • Visual Studio 2010 (บน Windows 7) คุณสามารถมี 1,011 ระดับก่อนที่จะได้รับข้อผิดพลาดนี้:

    ข้อผิดพลาดร้ายแรง C1026: parser stack overflow โปรแกรมซับซ้อนเกินไป

  • gcc (Ubuntu), 100k + *โดยไม่มีข้อผิดพลาด! ฉันเดาว่าฮาร์ดแวร์มีขีด จำกัด อยู่ที่นี่

(ทดสอบด้วยการประกาศตัวแปร)


5
อันที่จริงการผลิตสำหรับผู้ประกอบการเอกจะขวาซ้ำซึ่งหมายความว่า parser กะลดจะเปลี่ยน*โหนดทั้งหมดลงบนสแต็กก่อนที่จะสามารถลด
Kaz

28

ไม่มีตัวอย่างขีด จำกัด สามารถเช็คอินคือที่นี่

คำตอบขึ้นอยู่กับสิ่งที่คุณหมายถึงโดย "ระดับของพอยน์เตอร์" ถ้าคุณหมายถึง "คุณสามารถมีทางอ้อมได้กี่ระดับในการประกาศครั้งเดียว" คำตอบคือ "อย่างน้อย 12"

int i = 0;

int *ip01 = & i;

int **ip02 = & ip01;

int ***ip03 = & ip02;

int ****ip04 = & ip03;

int *****ip05 = & ip04;

int ******ip06 = & ip05;

int *******ip07 = & ip06;

int ********ip08 = & ip07;

int *********ip09 = & ip08;

int **********ip10 = & ip09;

int ***********ip11 = & ip10;

int ************ip12 = & ip11;

************ip12 = 1; /* i = 1 */

หากคุณหมายถึง "คุณสามารถใช้ตัวชี้กี่ระดับก่อนที่โปรแกรมจะอ่านยาก" นั่นเป็นเรื่องของรสนิยม แต่มีข้อ จำกัด การมีทางอ้อมสองระดับ (ตัวชี้ไปยังตัวชี้ไปยังบางสิ่ง) เป็นเรื่องปกติ ยิ่งไปกว่านั้นการคิดอย่างง่ายดายจะยากกว่านี้อีกเล็กน้อย อย่าทำอย่างนั้นเว้นแต่ทางเลือกจะเลวร้ายลง

ถ้าคุณหมายถึง "คุณมีตัวชี้ทางอ้อมได้กี่ระดับในขณะรันไทม์" ไม่มีข้อ จำกัด จุดนี้สำคัญอย่างยิ่งสำหรับรายการแบบวงกลมซึ่งแต่ละโหนดจะชี้ไปที่ถัดไป โปรแกรมของคุณสามารถติดตามตัวชี้ได้ตลอดไป


7
มีข้อ จำกัด เกือบแน่นอนเนื่องจากคอมไพเลอร์ต้องติดตามข้อมูลในหน่วยความจำที่ จำกัด ( g++ยกเลิกกับข้อผิดพลาดภายในที่ 98,242 ในเครื่องของฉันผมคาดหวังว่าขีด จำกัด ที่เกิดขึ้นจริงจะขึ้นอยู่กับเครื่องและโหลดฉันยังไม่ได้คาดหวังนี้จะมีปัญหาในรหัสจริง...)
เจมส์ Kanze

2
จ้ะ @MatthieuM : ฉันเพิ่งพิจารณาตามหลักเหตุผล :) ขอบคุณ James ที่ทำคำตอบให้เสร็จ
Nandkumar Tekale

3
รายการที่เชื่อมโยงไม่ได้เป็นตัวชี้ไปยังตัวชี้พวกมันเป็นตัวชี้ไปยังโครงสร้างที่มีตัวชี้ (หรือคุณจบลงด้วยการชี้ขาดที่ไม่จำเป็นจำนวนมาก)
Random832

1
@ Random832: Nand กล่าวว่า "ถ้าคุณหมายถึง" คุณสามารถมีตัวชี้ทางอ้อมได้กี่ระดับในขณะทำงาน "" ดังนั้นเขาจึงลบข้อ จำกัด เพียงแค่พูดถึงพอยน์เตอร์ถึงพอยน์เตอร์ (* n)
LarsH

1
ฉันไม่เข้าใจประเด็น: ' ไม่มีขีด จำกัด ลองดูตัวอย่างที่นี่ 'ตัวอย่างนี้ไม่มีข้อพิสูจน์ว่าไม่มีขีด จำกัด มันพิสูจน์ได้ว่าเป็นไปได้เพียงแค่การเบี่ยงเบนของ 12 ดาว ไม่ได้พิสูจน์circ_listตัวอย่างใด ๆเกี่ยวกับคำถามของ OP: ความจริงที่ว่าคุณสามารถสำรวจรายการพอยน์เตอร์ไม่ได้หมายความว่าคอมไพเลอร์สามารถรวบรวมทิศทางของดาวฤกษ์ได้
Alberto

24

จริงๆแล้วมันก็สนุกกว่าด้วยตัวชี้ไปยังฟังก์ชั่น

#include <cstdio>

typedef void (*FuncType)();

static void Print() { std::printf("%s", "Hello, World!\n"); }

int main() {
  FuncType const ft = &Print;
  ft();
  (*ft)();
  (**ft)();
  /* ... */
}

ดังที่แสดงไว้ที่นี่จะให้:

สวัสดีชาวโลก!
สวัสดีชาวโลก!
สวัสดีชาวโลก!

และมันไม่เกี่ยวข้องกับค่าใช้จ่ายรันไทม์ใด ๆ ดังนั้นคุณอาจจะสามารถซ้อนมันได้มากเท่าที่คุณต้องการ ... จนกว่าคอมไพเลอร์ของคุณจะฉายบนไฟล์


20

มีไม่ จำกัด ตัวชี้เป็นหน่วยความจำที่มีเนื้อหาเป็นที่อยู่
อย่างที่คุณพูด

int a = 10;
int *p = &a;

ตัวชี้ไปยังตัวชี้ยังเป็นตัวแปรที่มีที่อยู่ของตัวชี้อื่น

int **q = &p;

นี่qคือตัวชี้ไปยังตัวชี้ที่เก็บที่อยู่pซึ่งได้เก็บที่อยู่ของaแล้ว

ไม่มีอะไรพิเศษเป็นพิเศษเกี่ยวกับตัวชี้ไปยังตัวชี้
ดังนั้นจึงไม่มีข้อ จำกัด ในห่วงโซ่ของ poniters ซึ่งถือที่อยู่ของตัวชี้อื่น
กล่าวคือ

 int **************************************************************************z;

ได้รับอนุญาต.


17

นักพัฒนา C ++ ทุกคนควรเคยได้ยินโปรแกรมเมอร์ชื่อดังระดับสาม (ใน)

และดูเหมือนว่าจะมีเวทย์มนตร์ "กำแพงชี้" ซึ่งต้องพรางตัว

อ้างอิงจาก C2:

โปรแกรมเมอร์ระดับสามดาว

ระบบการจัดเรตสำหรับโปรแกรมเมอร์ C พอยน์เตอร์ของคุณทางอ้อมจะยิ่งมากขึ้น (เช่นยิ่ง "*" อยู่หน้าตัวแปรของคุณมากขึ้น) ชื่อเสียงของคุณก็จะยิ่งสูงขึ้นเท่านั้น โปรแกรมเมอร์ C ดาวที่ไม่มีอยู่จริงไม่มีอยู่จริงเนื่องจากโปรแกรมที่ไม่ใช่เรื่องไร้สาระทั้งหมดต้องการการใช้พอยน์เตอร์ ส่วนใหญ่เป็นโปรแกรมเมอร์ระดับหนึ่ง ในสมัยก่อน (อืมฉันยังเด็กดังนั้นอย่างน้อยพวกนี้ก็ดูเหมือนว่าสมัยเก่าสำหรับฉัน) บางครั้งจะพบชิ้นส่วนของรหัสที่ทำโดยโปรแกรมเมอร์ระดับสามดาวและตัวสั่นด้วยความกลัว บางคนถึงกับอ้างว่าพวกเขาเห็นโค้ดระดับสามดาวที่มีตัวชี้ฟังก์ชั่นที่เกี่ยวข้องโดยมีการอ้อมมากกว่าหนึ่งระดับ ฟังดูสมจริงเหมือนยูเอฟโอสำหรับฉัน


2
github.com/psi4/psi4public/blob/master/src/lib/libdpd/ …และสิ่งที่เขียนขึ้นโดยโปรแกรมเมอร์ระดับ 4 ดาว เขาเป็นเพื่อนของฉันด้วยและถ้าคุณอ่านรหัสมากพอคุณจะเข้าใจว่าทำไมมันถึงมีค่า 4 ดาว
เจฟฟ์

13

โปรดทราบว่ามีสองคำถามที่เป็นไปได้ที่นี่: เราสามารถบรรลุการชี้ทางอ้อมในระดับ C ในรูปแบบ C กี่ระดับและการเปลี่ยนทิศทางตัวชี้ระดับกี่ระดับที่เราสามารถบรรจุลงในตัวประกาศเดี่ยว

มาตรฐาน C อนุญาตสูงสุดที่จะกำหนดในอดีต (และให้ค่าขั้นต่ำสำหรับที่) แต่สามารถหลีกเลี่ยงได้ผ่านการประกาศ typedef หลาย:

typedef int *type0;
typedef type0 *type1;
typedef type1 *type2; /* etc */

ดังนั้นในที่สุดนี่คือปัญหาการใช้งานที่เชื่อมโยงกับแนวคิดว่าโปรแกรม C ขนาดใหญ่ / ซับซ้อนสามารถทำก่อนที่มันจะถูกปฏิเสธซึ่งเป็นคอมไพเลอร์ที่เฉพาะเจาะจงมาก


4

ฉันต้องการจะชี้ให้เห็นว่าการสร้างประเภทที่มีจำนวน * ตามอำเภอใจเป็นสิ่งที่สามารถเกิดขึ้นได้กับเทมเพลต metaprogramming ฉันลืมสิ่งที่ฉันทำอย่างแน่นอน แต่ก็มีข้อเสนอแนะว่าฉันสามารถสร้างประเภทที่แตกต่างใหม่ที่มีการจัดทำ meta บางอย่างระหว่างพวกเขาโดยใช้recursiveประเภท T

เทมเพลต Metaprogramming คือการสืบเชื้อสายอย่างช้าๆสู่ความบ้าคลั่งดังนั้นจึงไม่จำเป็นที่จะต้องแก้ตัวเมื่อสร้างประเภทที่มีการเปลี่ยนทิศทางหลายพันระดับ มันเป็นวิธีที่สะดวกในการทำแผนที่จำนวนเต็ม peano บนการขยายแม่แบบเป็นภาษาที่ใช้งานได้


ฉันยอมรับว่าฉันไม่เข้าใจคำตอบของคุณทั้งหมด แต่ให้พื้นที่ใหม่แก่ฉันในการสำรวจ :)
ankush981

3

กฎข้อ 17.5ของมาตรฐานMISRA Cปี 2004 ห้ามมิให้ตัวชี้ทางอ้อมมากกว่า 2 ระดับ


15
ค่อนข้างแน่ใจว่านั่นเป็นคำแนะนำสำหรับโปรแกรมเมอร์ไม่ใช่สำหรับคอมไพเลอร์
โคลจอห์นสัน

3
ฉันอ่านเอกสารที่มีกฎ 17.5 เกี่ยวกับการชี้ทางอ้อมมากกว่า 2 ระดับ และไม่จำเป็นต้องห้ามมากกว่า 2 ระดับ ระบุว่าควรมีการติดตามการพิจารณาคดีเนื่องจากมีมากกว่า 2 ระดับ"non-compliant"ตามมาตรฐานของพวกเขา คำหรือวลีที่สำคัญในการพิจารณาคดีคือการใช้คำ"should"จากข้อความนี้: Use of more than 2 levels of indirection can seriously impair the ability to understand the behavior of the code, and should therefore be avoided.นี่เป็นแนวทางที่กำหนดโดยองค์กรนี้ซึ่งตรงข้ามกับกฎที่กำหนดโดยมาตรฐานภาษา
ฟรานซิส Cugler

1

ไม่มีสิ่งเช่นขีด จำกัด ที่แท้จริงแต่มีข้อ จำกัด อยู่ พอยน์เตอร์ทั้งหมดเป็นตัวแปรที่มักจะเก็บไว้ในกองไม่ใช่กองไม่ได้กองสแต็กมักจะมีขนาดเล็ก (มันเป็นไปได้ที่จะเปลี่ยนขนาดในระหว่างการเชื่อมโยงบางอย่าง) สมมติว่าคุณมีสแต็คขนาด 4MB ขนาดปกติค่อนข้างเท่าไหร่ และสมมติว่าเรามีตัวชี้ขนาด 4 ไบต์ (ขนาดตัวชี้ไม่เหมือนกันขึ้นอยู่กับสถาปัตยกรรมการตั้งค่าเป้าหมายและคอมไพเลอร์)

ในกรณีนี้4 MB / 4 b = 1024จำนวนสูงสุดที่เป็นไปได้คือ 1048576 แต่เราไม่ควรเพิกเฉยต่อความจริงที่ว่ามีบางสิ่งที่อยู่ในกองซ้อน

อย่างไรก็ตามคอมไพเลอร์บางตัวอาจมีจำนวนลูกโซ่ตัวชี้สูงสุด แต่ขีด จำกัด คือขนาดสแต็ก ดังนั้นหากคุณเพิ่มขนาดสแต็กระหว่างการเชื่อมโยงกับอินฟินิตี้และมีเครื่องที่มีหน่วยความจำอินฟินิตี้ซึ่งรันระบบปฏิบัติการซึ่งจัดการกับหน่วยความจำนั้น

หากคุณใช้int *ptr = new int;และวางตัวชี้ของคุณลงในฮีปนั่นก็ไม่ได้เป็นวิธีที่ปกติที่จะ จำกัด ขนาดของฮีป

แก้ไขinfinity / 2 = infinityเพียงแค่รู้ว่า หากเครื่องมีหน่วยความจำมากกว่าขนาดตัวชี้จึงเพิ่มขึ้น ดังนั้นหากหน่วยความจำไม่มีที่สิ้นสุดและขนาดของตัวชี้เป็นอนันต์ดังนั้นจึงเป็นข่าวร้าย ... :)


4
A) พอยน์เตอร์สามารถเก็บไว้ในกอง ( new int*) B) int*และint**********มีขนาดเท่ากันอย่างน้อยก็ในสถาปัตยกรรมที่สมเหตุสมผล

@ Rightfold A) ใช่พอยน์เตอร์สามารถเก็บไว้ในกองได้ แต่มันจะแตกต่างกันมากเช่นการสร้าง container ที่เก็บพอยน์เตอร์ที่ชี้ไปยังตัวชี้หน้าที่ถัดไป B) แน่นอนint*และint**********มีขนาดเท่ากันฉันไม่ได้บอกว่ามันมีความแตกต่าง
ST3

2
จากนั้นฉันไม่เห็นว่าขนาดสแต็กเกี่ยวข้องกับระยะไกลได้อย่างไร

@ Rightfold ฉันคิดเกี่ยวกับการกระจายข้อมูลตามปกติเมื่อข้อมูลทั้งหมดอยู่ใน heap และใน stack เป็นเพียงตัวชี้ไปยังข้อมูลนั้น มันจะเป็นวิธีปกติแต่ฉันยอมรับว่าเป็นไปได้ที่จะนำพอยน์เตอร์ไปวางซ้อนกัน
ST3

"แน่นอน int * และ int ********** มีขนาดเท่ากัน" - มาตรฐานไม่รับประกันว่า (แม้ว่าฉันจะรู้ว่าไม่มีแพลตฟอร์มใดที่ไม่จริง)
Martin Bonner สนับสนุน Monica

0

ขึ้นอยู่กับสถานที่ที่คุณเก็บพอยน์เตอร์ หากอยู่ในสแต็กคุณจะมีขีด จำกัดค่อนข้างต่ำ หากคุณเก็บมันไว้ในกองคุณ จำกัด มากขึ้นมาก

ดูโปรแกรมนี้:

#include <iostream>

const int CBlockSize = 1048576;

int main() 
{
    int number = 0;
    int** ptr = new int*[CBlockSize];

    ptr[0] = &number;

    for (int i = 1; i < CBlockSize; ++i)
        ptr[i] = reinterpret_cast<int *> (&ptr[i - 1]);

    for (int i = CBlockSize-1; i >= 0; --i)
        std::cout << i << " " << (int)ptr[i] << "->" << *ptr[i] << std::endl;

    return 0;
}

มันสร้างพอยน์เตอร์ 1M และที่แสดงว่าอะไรชี้ไปที่สิ่งที่ง่ายต่อการสังเกตสิ่งที่โซ่ไปที่ตัวแปรแรก numberและแสดงให้เห็นว่าสิ่งที่ชี้ไปที่สิ่งที่มันเป็นเรื่องง่ายที่จะแจ้งให้ทราบล่วงหน้าสิ่งที่ห่วงโซ่ไปที่ตัวแปรแรก

BTW มันใช้92Kแรมดังนั้นลองจินตนาการว่าคุณจะไปได้ไกลแค่ไหน

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