Saya perhatikan ada yang aneh setelah kompilasi kode ini di komputer saya:
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
int a,b,c,d;
int e,f,g;
long int h;
printf("The addresses are:\n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x",
&a,&b,&c,&d,&e,&f,&g,&h);
return 0;
}
Hasilnya adalah sebagai berikut. Perhatikan bahwa antara setiap alamat int ada perbedaan 4-byte. Namun antara int terakhir dan int panjang ada perbedaan 12 byte:
Hello, World!
The addresses are:
da54dcac
da54dca8
da54dca4
da54dca0
da54dc9c
da54dc98
da54dc94
da54dc88
int
setelahh
dalam kode sumber. Compiler mungkin meletakkannya di celah, sebelumnyah
.sizeof
fungsi untuk itu.printf("size: %d ", sizeof(long));
%x
. Beruntung bagi Anda, itu terjadi untuk bekerja dengan benar pada platform Anda untuk melewatkan pointer pointer dengan format string yang diharapkanunsigned int
, tetapi pointer dan int adalah ukuran yang berbeda di banyak ABI. Gunakan%p
untuk mencetak petunjuk dalam kode portabel. (Sangat mudah untuk membayangkan suatu sistem di mana kode Anda akan mencetak bagian atas / bawah dari 4 petunjuk pertama, bukan setengah dari semua 8.)%zu
. @yoyo_fun untuk mencetak alamat yang digunakan%p
. Menggunakan format specifier yang salah memunculkan perilaku yang tidak terdefinisiJawaban:
Tidak butuh 12 byte, hanya butuh 8. Namun, penyelarasan default untuk int panjang 8 byte pada platform ini adalah 8 byte. Dengan demikian, kompiler perlu memindahkan int panjang ke alamat yang dapat dibagi oleh 8. Alamat "jelas", da54dc8c, tidak dapat dibagi 8 oleh karena itu kesenjangan 12 byte.
Anda harus dapat menguji ini. Jika Anda menambahkan int lain sebelum panjang, jadi ada 8 int, Anda harus menemukan bahwa int panjang akan disejajarkan ok tanpa bergerak. Sekarang hanya 8 byte dari alamat sebelumnya.
Mungkin perlu untuk menunjukkan bahwa, meskipun tes ini harus berhasil, Anda tidak harus bergantung pada variabel yang diatur dengan cara ini. Kompiler AC diizinkan untuk melakukan segala macam hal yang funky untuk membuat program Anda berjalan cepat termasuk memesan ulang variabel (dengan beberapa peringatan).
sumber
Ini karena kompiler Anda menghasilkan padding tambahan antar variabel untuk memastikan mereka tersejajarkan dengan benar dalam memori.
Pada kebanyakan prosesor modern, jika suatu nilai memiliki alamat yang merupakan kelipatan dari ukurannya, itu lebih efisien untuk mengaksesnya. Jika itu diletakkan
h
di tempat pertama yang tersedia, alamatnya akan 0xda54dc8c, yang bukan kelipatan 8, jadi akan kurang efisien untuk digunakan. Kompiler tahu tentang ini dan menambahkan sedikit ruang yang tidak digunakan antara dua variabel terakhir Anda untuk memastikan hal itu terjadi.sumber
Tes Anda belum tentu menguji apa yang Anda pikirkan, karena tidak ada persyaratan bahasa untuk menghubungkan alamat salah satu variabel lokal ini satu sama lain.
Anda harus meletakkan ini sebagai bidang dalam struct agar dapat menyimpulkan sesuatu tentang alokasi penyimpanan.
Variabel lokal tidak diperlukan untuk berbagi penyimpanan di samping satu sama lain dengan cara tertentu. Kompiler dapat memasukkan variabel sementara di mana saja di dalam tumpukan, misalnya, yang bisa berada di antara dua variabel lokal ini.
Sebaliknya, itu tidak akan diizinkan untuk memasukkan variabel sementara ke dalam sebuah struct, jadi jika Anda mencetak alamat-alamat dari bidang-bidang struct sebagai gantinya, Anda akan membandingkan item-item yang dimaksudkan dialokasikan dari memori logis yang sama dengan chuck (struct).
sumber