Maafkan jika pertanyaan ini naif. Pertimbangkan program berikut:
#include <stdio.h>
int main() {
int i = 1;
i = i + 2;
5;
i;
printf("i: %d\n", i);
}
Dalam contoh di atas, pernyataan 5;
dan i;
tampak benar-benar berlebihan, namun kode mengkompilasi tanpa peringatan atau kesalahan secara default (namun, gcc tidak memberikan warning: statement with no effect [-Wunused-value]
peringatan ketika dijalankan dengan -Wall
). Mereka tidak memiliki efek pada sisa program, jadi mengapa mereka dianggap pernyataan yang valid di tempat pertama? Apakah kompiler mengabaikannya? Apakah ada manfaat untuk mengizinkan pernyataan seperti itu?
;
. Ini akan menyulitkan bahasa untuk menambahkan lebih banyak aturan tentang kapan ekspresi tidak bisa menjadi pernyataanprintf()
? Pernyataan itu5;
pada dasarnya mengatakan "melakukan apa pun yang5
tidak (tidak ada) dan mengabaikan hasilnya. Pernyataan Andaprintf(...)
adalah 'melakukan apa pun yangprintf(...)
dilakukannya dan mengabaikan hasil (nilai kembali dariprintf()
)'. C memperlakukan orang-orang yang sama. Hal ini juga memungkinkan untuk kode seperti(void) i;
di manai
adalah parameter ke fungsi yang Anda gunakanvoid
untuk menandainya sebagai sengaja tidak digunakanprintf()
memang memiliki efek, bahkan jika Anda mengabaikan nilai itu akhirnya kembali. Sebaliknya5;
tidak memiliki efek sama sekali.Jawaban:
Satu manfaat untuk mengizinkan pernyataan seperti itu adalah dari kode yang dibuat oleh makro atau program lain, daripada ditulis oleh manusia.
Sebagai contoh, bayangkan fungsi
int do_stuff(void)
yang seharusnya mengembalikan 0 pada keberhasilan atau -1 pada kegagalan. Bisa jadi dukungan untuk "barang" adalah opsional, sehingga Anda dapat memiliki file header yang berfungsiSekarang bayangkan beberapa kode yang ingin melakukan hal-hal jika memungkinkan, tetapi mungkin atau mungkin tidak benar-benar peduli apakah itu berhasil atau gagal:
Ketika
STUFF_SUPPORTED
0, preprocessor akan memperluas panggilanfunc2
ke pernyataan yang baru saja dibacadan karenanya kompiler pass akan melihat hanya semacam pernyataan "berlebihan" yang tampaknya mengganggu Anda. Namun apa lagi yang bisa dilakukan seseorang? Jika Anda
#define do_stuff() // nothing
, maka kode difunc1
akan pecah. (Dan Anda masih akan memiliki pernyataan kosongfunc2
yang baru saja dibaca;
, yang mungkin bahkan lebih berlebihan.) Di sisi lain, jika Anda harus benar-benar mendefinisikando_stuff()
fungsi yang mengembalikan -1, Anda dapat mengeluarkan biaya panggilan fungsi tanpa alasan.sumber
((void)0)
.assert
.Pernyataan Sederhana dalam C diakhiri dengan titik koma.
Pernyataan Sederhana dalam C adalah ekspresi. Ekspresi adalah kombinasi dari variabel, konstanta dan operator. Setiap ekspresi menghasilkan beberapa nilai tipe tertentu yang dapat ditetapkan ke variabel.
Setelah mengatakan bahwa beberapa "kompiler pintar" mungkin membuang 5; dan saya; pernyataan.
sumber
void
tidak memiliki nilai.Pernyataan tanpa efek diizinkan karena akan lebih sulit untuk melarangnya daripada mengizinkannya. Ini lebih relevan ketika C pertama kali dirancang dan kompiler lebih kecil dan lebih sederhana.
Sebuah pernyataan ekspresi terdiri dari sebuah ekspresi yang diikuti dengan titik koma. Perilakunya adalah untuk mengevaluasi ekspresi dan membuang hasilnya (jika ada). Biasanya tujuannya adalah bahwa evaluasi ekspresi memiliki efek samping, tetapi tidak selalu mudah atau bahkan mungkin untuk menentukan apakah ekspresi yang diberikan memiliki efek samping.
Misalnya, panggilan fungsi adalah ekspresi, jadi panggilan fungsi diikuti oleh tanda titik koma adalah pernyataan. Apakah pernyataan ini memiliki efek samping?
Tidak mungkin untuk mengatakan tanpa melihat implementasinya
some_function
.Bagaimana dengan ini?
Mungkin tidak - tetapi jika
obj
didefinisikan sebagaivolatile
, maka itu terjadi.Mengizinkan ekspresi apa pun dibuat menjadi ekspresi-ekspresi dengan menambahkan tanda titik koma membuat definisi bahasa lebih sederhana. Mewajibkan ekspresi memiliki efek samping akan menambah kerumitan definisi bahasa dan ke kompiler. C dibangun di atas seperangkat aturan yang konsisten (pemanggilan fungsi adalah ekspresi, penugasan adalah ekspresi, ekspresi yang diikuti oleh tanda titik koma adalah pernyataan) dan memungkinkan pemrogram melakukan apa yang mereka inginkan tanpa mencegah mereka melakukan hal-hal yang mungkin atau mungkin tidak masuk akal.
sumber
Pernyataan yang Anda daftarkan tanpa efek adalah contoh pernyataan ekspresi , yang sintaksnya diberikan di bagian 6.8.3p1 dari standar C sebagai berikut:
Semua bagian 6.5 didedikasikan untuk definisi ekspresi, tetapi secara longgar ekspresi terdiri dari konstanta dan pengidentifikasi yang terkait dengan operator. Khususnya, suatu ekspresi mungkin atau mungkin tidak mengandung operator penugasan dan mungkin atau mungkin tidak mengandung panggilan fungsi.
Jadi setiap ekspresi yang diikuti oleh tanda titik koma memenuhi syarat sebagai pernyataan ekspresi. Bahkan, setiap baris ini dari kode Anda adalah contoh pernyataan ekspresi:
Beberapa operator berisi efek samping seperti seperangkat operator penugasan dan operator kenaikan / penurunan pra / pasca, dan operator panggilan fungsi
()
mungkin memiliki efek samping tergantung pada fungsi yang dimaksud. Namun tidak ada persyaratan bahwa salah satu operator harus memiliki efek samping.Ini contoh lain:
Ini memanggil fungsi dan membuang hasilnya, sama seperti panggilan
printf
dalam contoh Anda tetapi tidak sepertiprintf
fungsi panggil itu sendiri tidak memiliki efek samping.sumber
Terkadang pernyataan seperti itu sangat berguna:
Atau ketika manual referensi memberitahu kita untuk hanya membaca register untuk mengarsipkan sesuatu - misalnya untuk menghapus atau mengatur beberapa flag (situasi yang sangat umum di dunia UC)
https://godbolt.org/z/6wjh_5
sumber
*SREG
volatile,*SREG;
tidak memiliki efek pada model yang ditentukan oleh standar C. Standar C menyatakan bahwa ia memiliki efek samping yang dapat diamati.