Mengapa array panjang variabel tidak menjadi bagian dari standar C ++?

326

Saya belum pernah menggunakan C dalam beberapa tahun terakhir. Ketika saya membaca pertanyaan ini hari ini saya menemukan beberapa sintaks C yang tidak saya kenal.

Rupanya di C99 sintaks berikut ini valid:

void foo(int n) {
    int values[n]; //Declare a variable length array
}

Ini sepertinya fitur yang sangat berguna. Apakah pernah ada diskusi tentang menambahkannya ke standar C ++, dan jika demikian, mengapa itu dihilangkan?

Beberapa alasan potensial:

  • Berbulu bagi vendor kompiler untuk diimplementasikan
  • Tidak kompatibel dengan beberapa bagian standar lainnya
  • Fungsi dapat ditiru dengan konstruksi C ++ lainnya

Standar C ++ menyatakan bahwa ukuran array harus berupa ekspresi konstan (8.3.4.1).

Ya, tentu saja saya menyadari bahwa dalam contoh mainan yang dapat digunakan std::vector<int> values(m);, tetapi ini mengalokasikan memori dari tumpukan dan bukan tumpukan. Dan jika saya ingin array multidimensi seperti:

void foo(int x, int y, int z) {
    int values[x][y][z]; // Declare a variable length array
}

yang vectorversi menjadi cukup canggung:

void foo(int x, int y, int z) {
    vector< vector< vector<int> > > values( /* Really painful expression here. */);
}

Irisan, baris, dan kolom juga berpotensi tersebar di seluruh memori.

Melihat diskusi comp.std.c++itu jelas bahwa pertanyaan ini cukup kontroversial dengan beberapa nama kelas berat di kedua sisi argumen. Jelas tidak jelas bahwa std::vectorselalu solusi yang lebih baik.

Andreas Brinck
sumber
3
Hanya ingin tahu, mengapa perlu dialokasikan di tumpukan? Apakah Anda yang takut menumpuk masalah kinerja alokasi?
Dimitri C.
32
@ Dimitri Tidak juga, tetapi tidak dapat disangkal bahwa alokasi tumpukan akan lebih cepat daripada alokasi tumpukan. Dan dalam beberapa kasus ini mungkin penting.
Andreas Brinck
11
Keuntungan utama dari array panjang variabel bahwa semua data berdekatan sehingga ketika Anda mengulang melalui array ini Anda membaca dan menulis byte di samping satu sama lain. Data Anda diambil ke dalam cache dan cpu dapat bekerja di dalamnya tanpa mengambil dan mengirim byte ke / dari memori.
Calmarius
4
Array panjang variabel juga dapat digunakan untuk menggantikan konstanta preprosesor dengan variabel konstanta statis. Juga di C Anda tidak memiliki opsi lain untuk VLA, dan kadang-kadang diperlukan untuk menulis kode C / C ++ portabel (kompatibel dengan kedua kompiler).
Yury
2
selain itu, tampaknya clang ++ memungkinkan VLA.
user3426763

Jawaban:

204

Baru-baru ini ada diskusi tentang ini dimulai di usenet: Mengapa tidak ada VLA di C ++ 0x .

Saya setuju dengan orang-orang yang tampaknya setuju bahwa harus membuat potensi array besar di stack, yang biasanya hanya memiliki sedikit ruang, tidak baik. Argumennya adalah, jika Anda tahu ukurannya sebelumnya, Anda bisa menggunakan array statis. Dan jika Anda tidak tahu ukurannya sebelumnya, Anda akan menulis kode yang tidak aman.

C99 VLA dapat memberikan manfaat kecil karena dapat membuat array kecil tanpa membuang ruang atau memanggil konstruktor untuk elemen yang tidak digunakan, tetapi mereka akan memperkenalkan perubahan yang agak besar pada sistem tipe (Anda harus dapat menentukan tipe tergantung pada nilai runtime - ini belum ada dalam C ++ saat ini, kecuali untuk newspecifier tipe-operator, tetapi mereka diperlakukan secara khusus, sehingga runtime-ness tidak luput dari ruang lingkup newoperator).

Anda dapat menggunakan std::vector, tetapi tidak persis sama, karena menggunakan memori dinamis, dan membuatnya menggunakan stack-dialokasikan sendiri tidak mudah (perataan adalah masalah juga). Ini juga tidak memecahkan masalah yang sama, karena vektor adalah wadah yang dapat diubah ukurannya, sedangkan VLA berukuran tetap. The C ++ Dinamis Array usulan ini dimaksudkan untuk memperkenalkan solusi berbasis perpustakaan, sebagai alternatif untuk bahasa berbasis VLA. Namun, itu tidak akan menjadi bagian dari C ++ 0x, sejauh yang saya tahu.

Johannes Schaub - litb
sumber
22
+1 dan diterima. Namun satu komentar, saya pikir argumen keselamatan agak lemah karena ada begitu banyak cara lain untuk menyebabkan stack overflow. Argumen keamanan dapat digunakan untuk mendukung posisi yang Anda seharusnya tidak pernah menggunakan rekursi dan bahwa Anda harus mengalokasikan semua objek dari heap.
Andreas Brinck
17
Jadi Anda mengatakan bahwa karena ada cara lain untuk menyebabkan stack overflow, sebaiknya kita mendorong lebih dari mereka?
jalf
3
@ Andreas, setuju tentang kelemahannya. Tetapi untuk rekursi, dibutuhkan sejumlah besar panggilan sampai tumpukan habis, dan jika itu bisa terjadi, orang akan menggunakan iterasi. Seperti yang dikatakan beberapa orang di utas usenet, ini bukan argumen terhadap VLA dalam semua kasus, karena kadang-kadang Anda pasti tahu batas atas. Tetapi dalam kasus-kasus itu, dari apa yang saya lihat array statis dapat sama-sama mencukupi, karena tidak akan menyia-nyiakan banyak ruang (jika mau , maka Anda benar-benar harus bertanya apakah area stack cukup besar lagi).
Johannes Schaub - litb
10
Juga lihat jawaban Matt Austern di utas itu: Spesifikasi bahasa VLA mungkin akan jauh lebih kompleks untuk C ++, karena jenis pencocokan yang lebih ketat di C ++ (contoh: C memungkinkan menetapkan a T(*)[]ke T(*)[N]- dalam C ++ ini tidak diperbolehkan, karena C ++ tidak tahu tentang "kompatibilitas tipe" - ini membutuhkan kecocokan yang tepat), ketikkan parameter, pengecualian, konstruktor dan penghancur dan barang. Saya tidak yakin apakah manfaat VLA akan benar-benar membayar semua pekerjaan itu. Tapi kemudian, saya belum pernah menggunakan VLA dalam kehidupan nyata, jadi saya mungkin tidak tahu kasus penggunaan yang baik untuk mereka.
Johannes Schaub - litb
1
@ Membantu: Mungkin apa yang terbaik untuk itu adalah tipe yang berperilaku seperti vectortetapi membutuhkan pola penggunaan LIFO yang tetap dan mempertahankan satu atau lebih per-thread buffer yang dialokasikan secara statis yang umumnya berukuran sesuai dengan total alokasi terbesar yang dimiliki thread. pernah digunakan, tetapi yang bisa dipangkas secara eksplisit. "Alokasi" normal dalam kasus umum tidak memerlukan lebih dari salinan pointer, pengurangan pointer-dari-pointer, perbandingan integer, dan penambahan pointer; de-alokasi hanya membutuhkan salinan pointer. Tidak jauh lebih lambat dari VLA.
supercat
217

(Latar belakang: Saya memiliki pengalaman menerapkan kompiler C dan C ++.)

Panjang array variabel di C99 pada dasarnya salah langkah. Untuk mendukung VLA, C99 harus membuat konsesi berikut ini untuk akal sehat:

  • sizeof xtidak lagi selalu konstan waktu kompilasi; kompiler terkadang harus menghasilkan kode untuk mengevaluasi sizeofekspresi-saat runtime.

  • Membiarkan Vlas dua dimensi ( int A[x][y]) diperlukan sintaks baru untuk menyatakan fungsi yang mengambil 2D Vlas sebagai parameter: void foo(int n, int A[][*]).

  • Tidak terlalu penting di dunia C ++, tetapi sangat penting bagi audiens target C dari pemrogram sistem tertanam, mendeklarasikan VLA berarti mengompres tumpukan stack Anda secara sewenang - wenang . Ini adalah stack-overflow dan crash yang dijamin . (Kapan saja Anda menyatakan int A[n], Anda secara implisit menyatakan bahwa Anda memiliki 2GB stack untuk cadangan. Setelah semua, jika Anda tahu " npasti kurang dari 1000 di sini", maka Anda hanya akan menyatakan int A[1000]. Mengganti integer 32-bit nuntuk 1000adalah pengakuan Anda tidak tahu seperti apa perilaku program Anda seharusnya.)

Oke, jadi mari kita beralih ke berbicara tentang C ++ sekarang. Dalam C ++, kami memiliki perbedaan kuat yang sama antara "sistem tipe" dan "sistem nilai" yang dilakukan C89 ... tapi kami benar-benar mulai mengandalkannya dengan cara yang tidak dimiliki C. Sebagai contoh:

template<typename T> struct S { ... };
int A[n];
S<decltype(A)> s;  // equivalently, S<int[n]> s;

Jika nbukan konstanta waktu kompilasi (yaitu, jika Ajenisnya diubah secara variatif), lalu apa jenisnya S? Apakah Stipe juga hanya akan ditentukan saat runtime?

Bagaimana dengan ini:

template<typename T> bool myfunc(T& t1, T& t2) { ... };
int A1[n1], A2[n2];
myfunc(A1, A2);

Kompiler harus menghasilkan kode untuk beberapa contoh myfunc. Seperti apa kode itu? Bagaimana kita dapat secara statis menghasilkan kode itu, jika kita tidak tahu tipe A1pada waktu kompilasi?

Lebih buruk lagi, bagaimana jika ternyata pada saat runtime itu n1 != n2, jadi begitu !std::is_same<decltype(A1), decltype(A2)>()? Dalam hal ini, panggilan kemyfunc bahkan tidak boleh dikompilasi , karena pengurangan tipe template harus gagal! Bagaimana mungkin kita meniru perilaku itu saat runtime?

Pada dasarnya, C ++ bergerak ke arah mendorong semakin banyak keputusan ke dalam waktu kompilasi : pembuatan kode templat, constexprevaluasi fungsi, dan sebagainya. Sementara itu, C99 sibuk mendorong keputusan waktu kompilasi tradisional (misalnya sizeof) ke dalam runtime . Dengan pemikiran ini, apakah itu benar-benar bahkan masuk akal untuk mengeluarkan upaya berusaha untuk mengintegrasikan Vlas C99 bergaya dalam C ++?

Seperti yang sudah ditunjukkan oleh setiap penjawab lain, C ++ menyediakan banyak mekanisme alokasi-tumpukan ( std::unique_ptr<int[]> A = new int[n];atau std::vector<int> A(n);menjadi yang jelas) ketika Anda benar-benar ingin menyampaikan gagasan "Saya tidak tahu berapa banyak RAM yang mungkin saya butuhkan." Dan C ++ menyediakan model penanganan pengecualian yang bagus untuk menghadapi situasi yang tak terhindarkan bahwa jumlah RAM yang Anda butuhkan lebih besar dari jumlah RAM yang Anda miliki. Tapi semoga jawaban ini memberi Anda ide bagus mengapa VLA gaya C99 tidak cocok untuk C ++ - dan bahkan tidak cocok untuk C99. ;)


Untuk lebih lanjut tentang topik ini, lihat N3810 "Alternatif untuk Ekstensi Array" , makalah Bjarne Stroustrup Oktober 2013 tentang VLA. Pjar Bjarne sangat berbeda dengan milikku; N3810 lebih fokus pada menemukan ish C ++ yang bagus sintaksis untuk hal-hal, dan pada mengecilkan penggunaan array mentah di C ++, sedangkan saya lebih fokus pada implikasi untuk metaprogramming dan sistem types. Saya tidak tahu apakah dia menganggap implikasi metaprogramming / sistem huruf diselesaikan, dipecahkan, atau hanya tidak menarik.


Sebuah posting blog yang bagus yang mengenai banyak poin yang sama ini adalah "Penggunaan Array Panjang Variabel yang Sah" (Chris Wellons, 2019-10-27).

Quuxplusone
sumber
15
Saya setuju VLA salah. Yang jauh lebih banyak diimplementasikan, dan jauh lebih bermanfaat, alloca()seharusnya sudah distandarisasi dalam C99. VLA adalah apa yang terjadi ketika komite standar melompat lebih dulu dari implementasi, bukan sebaliknya.
MadScientist
10
Sistem tipe yang dimodifikasi secara variatif adalah tambahan IMO yang bagus, dan tidak ada poin Anda yang melanggar akal sehat. (1) standar C tidak membedakan antara "waktu kompilasi" dan "waktu berjalan" jadi ini bukan masalah; (2) Ini *adalah opsional, Anda dapat (dan harus) menulis int A[][n]; (3) Anda dapat menggunakan sistem tipe tanpa benar-benar mendeklarasikan VLA apa pun. Sebagai contoh, suatu fungsi dapat menerima array dengan tipe yang dimodifikasi secara variatif, dan dapat dipanggil dengan array 2-D non-VLA dengan dimensi yang berbeda. Namun Anda membuat poin yang valid di bagian akhir posting Anda.
MM
3
"mendeklarasikan VLA berarti chomping bongkahan besar stack Anda secara sewenang-wenang. Ini dijamin stack-overflow dan crash. (Setiap kali Anda mendeklarasikan ke dalam A [n], Anda secara implisit menyatakan bahwa Anda memiliki 2GB stack untuk cadangan" secara empiris palsu Saya baru saja menjalankan program VLA dengan stack yang jauh lebih sedikit dari 2GB tanpa stack overflow
Jeff
3
@ Jeff: Berapa nilai maksimum ndalam kasus uji Anda, dan berapa ukuran tumpukan Anda? Saya sarankan Anda mencoba memasukkan nilai nsetidaknya sebesar ukuran tumpukan Anda. (Dan jika tidak ada cara bagi pengguna untuk mengontrol nilai ndalam program Anda, maka saya sarankan Anda hanya menyebarkan nilai maksimum nlangsung ke dalam deklarasi: menyatakan int A[1000]atau apa pun yang Anda butuhkan. VLA hanya diperlukan, dan hanya berbahaya, ketika nilai maksimum dari ntidak dibatasi oleh konstanta waktu kompilasi kecil apa pun.)
Quuxplusone
2
Karena alokasi () dapat diimplementasikan menggunakan intrinsik seperti itu, menurut definisi benar bahwa alokasi () dapat diimplementasikan pada platform apa pun, sebagai fungsi standar kompiler. Tidak ada alasan bahwa kompilator tidak dapat mendeteksi instance pertama dari alokasi () dan mengatur untuk jenis tanda dan rilis yang akan tertanam dalam kode, dan tidak ada alasan mengapa kompiler tidak dapat mengimplementasikan alokasi () menggunakan heap jika itu tidak bisa dilakukan dengan stack. Apa yang sulit / non-portabel adalah telah mengalokasikan () diimplementasikan di atas kompiler C, sehingga bekerja di berbagai kompiler dan sistem operasi.
MadScientist
26

Anda selalu dapat menggunakan alokasi () untuk mengalokasikan memori pada stack saat runtime, jika Anda menginginkan:

void foo (int n)
{
    int *values = (int *)alloca(sizeof(int) * n);
}

Sedang dialokasikan pada tumpukan menyiratkan bahwa itu akan secara otomatis dibebaskan ketika tumpukan dibuka.

Catatan cepat: Seperti yang disebutkan dalam halaman manual Mac OS X untuk alokasi (3), "Fungsi alokasi () bergantung pada mesin dan kompiler; penggunaannya tidak diganggu." Asal kamu tahu.

PfhorSlayer
sumber
4
Juga, ruang lingkup untuk dialokasikan () adalah seluruh fungsi, bukan hanya blok kode yang berisi variabel. Jadi menggunakannya di dalam lingkaran itu akan terus meningkatkan tumpukan. VLA tidak memiliki masalah ini.
sashoalm
3
Namun, VLA yang memiliki lingkup blok yang dilampirkan berarti mereka secara signifikan kurang bermanfaat daripada alokasi () dengan cakupan seluruh fungsi. Pertimbangkan: if (!p) { p = alloca(strlen(foo)+1); strcpy(p, foo); } Ini tidak dapat dilakukan dengan VLA, justru karena ruang lingkup blok mereka.
MadScientist
1
Itu tidak menjawab pertanyaan mengapa OP . Terlebih lagi, ini adalah Csolusi yang mirip, dan bukan yang sebenarnya C++.
Adrian W
13

Dalam pekerjaan saya sendiri, saya menyadari bahwa setiap kali saya menginginkan sesuatu seperti array atau alokasi otomatis panjang variabel (), saya tidak terlalu peduli bahwa memori secara fisik terletak di cpu stack, hanya saja memori itu berasal dari beberapa pengalokasi tumpukan yang tidak menimbulkan perjalanan lambat ke tumpukan umum. Jadi saya punya objek per-thread yang memiliki beberapa memori yang dapat mendorong / pop buffer ukuran variabel. Pada beberapa platform saya membiarkan ini tumbuh melalui mmu. Platform lain memiliki ukuran tetap (biasanya disertai dengan tumpukan cpu ukuran tetap juga karena tidak ada mmu). Satu platform yang bekerja dengan saya (konsol permainan genggam) memiliki tumpukan cpu kecil yang berharga karena berada di memori yang langka dan cepat.

Saya tidak mengatakan bahwa mendorong buffer berukuran variabel ke dalam cpu stack tidak pernah diperlukan. Jujur saya kaget ketika saya menemukan ini bukan standar, karena sepertinya konsep itu cukup cocok dengan bahasa. Bagi saya, persyaratan "ukuran variabel" dan "harus secara fisik terletak pada cpu stack" tidak pernah muncul bersamaan. Sudah tentang kecepatan, jadi saya membuat semacam "tumpukan paralel untuk buffer data".

Eric
sumber
12

Ada situasi di mana mengalokasikan memori tumpukan sangat mahal dibandingkan dengan operasi yang dilakukan. Contohnya adalah matriks matematika. Jika Anda bekerja dengan matriks bertubuh kecil mengatakan 5 hingga 10 elemen dan melakukan banyak aritmatika, biaya overhead malloc akan sangat signifikan. Pada saat yang sama membuat ukuran konstanta waktu kompilasi tampaknya sangat boros dan tidak fleksibel.

Saya pikir C ++ sangat tidak aman dalam dirinya sendiri sehingga argumen untuk "mencoba untuk tidak menambahkan lebih banyak fitur yang tidak aman" tidak terlalu kuat. Di sisi lain, karena C ++ bisa dibilang adalah fitur bahasa pemrograman runtime paling efisien yang membuatnya selalu lebih berguna: Orang yang menulis program kritis kinerja sebagian besar akan menggunakan C ++, dan mereka membutuhkan kinerja sebanyak mungkin. Memindahkan barang dari tumpukan ke tumpukan adalah salah satu kemungkinannya. Mengurangi jumlah heap block adalah hal lain. Mengizinkan VLA sebagai anggota objek akan menjadi salah satu cara untuk mencapai ini. Saya sedang mengerjakan saran semacam itu. Memang agak rumit untuk diterapkan, diakui, tetapi tampaknya cukup bisa dilakukan.

Bengt Gustafsson
sumber
12

Tampaknya akan tersedia di C ++ 14:

https://en.wikipedia.org/wiki/C%2B%2B14#Runtime-sized_one_dimensional_arrays

Pembaruan: Tidak berhasil masuk ke C ++ 14.

Viktor Sehr
sumber
menarik. Herb Sutter membahasnya di sini di bawah Dynamic Array : isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting (ini adalah referensi untuk informasi wikipedia)
Default
1
"Array dan dynarray berukuran run-time telah dipindahkan ke spesifikasi teknis Ekstensi Array" tulis 78.86.152.103 di Wikipedia pada 18 Januari 2014: en.wikipedia.org/w/…
strager
10
Wikipedia bukan referensi normatif :) Proposal ini tidak membuatnya menjadi C ++ 14.
MM
2
@ ViktorSehr: Apa status wrt C ++ 17 ini?
einpoklum
@einpoklum Tidak tahu, gunakan boost :: container :: static_vector
Viktor Sehr
7

Ini dianggap untuk dimasukkan dalam C ++ / 1x, tetapi dibatalkan (ini adalah koreksi dari apa yang saya katakan sebelumnya).

Lagipula itu akan kurang berguna di C ++ karena kita sudah harus std::vectormengisi peran ini.

philsquared
sumber
42
Tidak, kami tidak, std :: vector tidak mengalokasikan data pada stack. :)
Kos
7
"tumpukan" adalah detail implementasi; kompiler dapat mengalokasikan memori dari mana saja selama jaminan tentang umur objek terpenuhi.
MM
1
@ MM: Cukup adil, tetapi dalam praktiknya kami masih tidak bisa menggunakan std::vectoralih-alih, katakanlah alloca(),.
einpoklum
@einpoklum dalam hal mendapatkan hasil yang benar untuk program Anda, Anda bisa. Kinerja adalah masalah kualitas implementasi
MM
1
@ MM kualitas implementasi tidak portabel. dan jika Anda tidak membutuhkan kinerja, Anda tidak menggunakan c ++ di tempat pertama
sobat
3

Gunakan std :: vector untuk ini. Sebagai contoh:

std::vector<int> values;
values.resize(n);

Memori akan dialokasikan pada heap, tetapi ini hanya memiliki sedikit kekurangan kinerja. Selain itu, sebaiknya tidak mengalokasikan data besar pada tumpukan, karena ukurannya agak terbatas.

Dimitri C.
sumber
4
Aplikasi utama untuk array panjang variabel adalah evaluasi polinomial tingkat arbitrer. Dalam hal itu, "kelemahan kinerja kecil" Anda berarti "kode berjalan lima kali lebih lambat dalam kasus-kasus tertentu." Itu tidak kecil.
Membantu
1
Mengapa tidak Anda gunakan saja std::vector<int> values(n);? Dengan menggunakan resizesetelah konstruksi, Anda melarang jenis yang tidak dapat dipindahkan.
LF
1

C99 memungkinkan VLA. Dan itu menempatkan beberapa batasan tentang cara mendeklarasikan VLA. Untuk detail, lihat 6.7.5.2 dari standar. C ++ melarang VLA. Tetapi g ++ memungkinkannya.

Jingguo Yao
sumber
Bisakah Anda memberikan tautan ke paragraf standar yang Anda tunjukkan?
Vincent
0

Array seperti ini adalah bagian dari C99, tetapi bukan bagian dari standar C ++. seperti yang orang lain katakan, vektor selalu merupakan solusi yang jauh lebih baik, yang mungkin mengapa array ukuran variabel tidak dalam standar C ++ (atau dalam standar C ++ 0x yang diusulkan).

BTW, untuk pertanyaan tentang "mengapa" standar C ++ seperti itu, newsgroup Usenet yang dimoderatori comp.std.c ++ adalah tempat untuk dituju.


sumber
6
-1 Vektor tidak selalu lebih baik. Seringkali ya. Selalu, tidak. Jika Anda hanya membutuhkan array kecil, ada di platform di mana ruang tumpukan lambat, dan implementasi vektor perpustakaan Anda menggunakan ruang tumpukan, maka fitur ini mungkin lebih baik jika ada.
Patrick M
-1

Jika Anda tahu nilai pada waktu kompilasi Anda dapat melakukan hal berikut:

template <int X>
void foo(void)
{
   int values[X];

}

Sunting: Anda dapat membuat vektor yang menggunakan pengalokasi tumpukan (Alokasi), karena pengalokasi adalah parameter templat.

Edouard A.
sumber
18
Jika Anda tahu nilainya pada waktu kompilasi, Anda tidak memerlukan template sama sekali. Cukup gunakan X langsung di fungsi non-templat Anda.
Rob Kennedy
3
Terkadang penelepon tahu pada waktu kompilasi dan callee tidak, itulah gunanya templat. Tentu saja, dalam kasus umum, tidak ada yang tahu X sampai run-time.
Qwertie
Anda tidak dapat menggunakan pengalokasian dalam pengalokasian STL - memori yang dialokasikan dari pengalokasian akan dibebaskan ketika bingkai tumpukan dihancurkan - saat itulah metode yang harus mengalokasikan pengembalian memori.
Oliver
-5

Saya punya solusi yang benar-benar bekerja untuk saya. Saya tidak ingin mengalokasikan memori karena fragmentasi pada rutin yang perlu dijalankan berkali-kali. Jawabannya sangat berbahaya, jadi gunakan dengan risiko Anda sendiri, tetapi memanfaatkan perakitan untuk menghemat ruang di tumpukan. Contoh saya di bawah ini menggunakan array karakter (jelas variabel berukuran lain akan membutuhkan lebih banyak memori).

void varTest(int iSz)
{
    char *varArray;
    __asm {
        sub esp, iSz       // Create space on the stack for the variable array here
        mov varArray, esp  // save the end of it to our pointer
    }

    // Use the array called varArray here...  

    __asm {
        add esp, iSz       // Variable array is no longer accessible after this point
    } 
}

Bahaya di sini banyak tetapi saya akan menjelaskan beberapa: 1. Mengubah ukuran variabel setengah jalan akan membunuh posisi stack 2. Melebihi batas array akan menghancurkan variabel lain dan kode yang mungkin 3. Ini tidak bekerja dalam 64 bit build ... perlu perakitan berbeda untuk yang itu (tapi makro mungkin bisa menyelesaikan masalah itu). 4. Khusus kompiler (mungkin mengalami kesulitan bergerak di antara kompiler). Saya belum mencoba jadi saya benar-benar tidak tahu.

Alan
sumber
... dan jika Anda ingin menggulung ini sendiri, mungkin menggunakan kelas RAII?
einpoklum
Anda cukup menggunakan boost :: container :: static_vector Engkau.
Viktor Sehr
Ini tidak memiliki padanan untuk kompiler lain yang memiliki rakitan lebih mentah dari MSVC. VC mungkin akan memahami bahwa itu espberubah dan akan menyesuaikan aksesnya ke stack, tetapi dalam GCC misalnya Anda hanya akan mematahkannya - setidaknya jika Anda menggunakan optimasi dan -fomit-frame-pointerkhususnya.
Ruslan