我一直想知道 C 中的復合文字,它們會創建重復的副本嗎?
以下面兩個例子為例。兩者之間唯一的區別是幾行代碼,分別
book->book_id = book_id;
book->price = price;
book->isbn = isbn;
在第一個示例中,并且
*book = (Book) {
.book_id = book_id,
.price = price,
.isbn = isbn
};
在第二個例子中。
我的問題很簡單:第二個示例是先在堆疊中Book分配一個結構,然后將其復制到堆中,還是第二個示例的行為與第一個示例完全相同,只是填充已經在堆中分配的結構而不接觸堆疊?
示例 1
#include <stdio.h>
#include <stdlib.h>
typedef struct Book_T {
unsigned int book_id;
unsigned int price;
long unsigned int isbn;
} Book;
Book * new_book (
const unsigned int book_id,
const unsigned int price,
const long unsigned int isbn
) {
Book * book = malloc(sizeof(Book));
if (!book) {
return NULL;
}
book->book_id = book_id;
book->price = price;
book->isbn = isbn;
return book;
}
int main (
const int argc,
const char * argv[]
) {
Book * my_book = new_book(12944, 39, 9783161484100);
if (!my_book) {
fprintf(stderr, "Error allocating memory\n");
return 1;
}
/* Do something with `my_book`... */
free(my_book);
return 0;
}
示例 2
#include <stdio.h>
#include <stdlib.h>
typedef struct Book_T {
unsigned int book_id;
unsigned int price;
long unsigned int isbn;
} Book;
Book * new_book (
const unsigned int book_id,
const unsigned int price,
const long unsigned int isbn
) {
Book * book = malloc(sizeof(Book));
if (!book) {
return NULL;
}
*book = (Book) {
.book_id = book_id,
.price = price,
.isbn = isbn
};
return book;
}
int main (
const int argc,
const char * argv[]
) {
Book * my_book = new_book(12944, 39, 9783161484100);
if (!my_book) {
fprintf(stderr, "Error allocating memory\n");
return 1;
}
/* Do something with `my_book`... */
free(my_book);
return 0;
}
uj5u.com熱心網友回復:
在抽象機器(這是 C 的定義方式)中,塊范圍內的復合文字在自動存盤中創建一個物件。該物件將在函式結束時被銷毀。
“堆疊”和“堆”是實作細節(某些實作沒有)。對實作的唯一要求是產生與抽象機相同的可觀察行為,它不必復制抽象機的記憶體使用情況。因此,真機可以為您的兩個示例生成相同的可執行檔案。
uj5u.com熱心網友回復:
如果編譯器可以看到將使用常量文字物件完成的所有操作,那么它可能會省略為其保留和釋放空間的代碼。例如,給定:
struct S foo;
...
foo = (struct S foo){1,2,3};
編譯器可以生成代碼,將 1、2 和 3 直接存盤到的第一項中,foo并將零存盤到其余項(如果有),而不是生成新的臨時物件并復制它。
不幸的是,在代碼獲取復合文字的地址并以編譯器無法看到的方式使用它的情況下,沒有辦法讓編譯器避免構造臨時物件。給定例如
extern void someFunction(struct foo const *p);
...
someOutSideFunction(&(struct foo){1,2,3});
不允許編譯器替換:
extern void someFunction(struct foo const *p);
...
static struct foo const __const24601 = {1,2,3};
someOutSideFunction(&__const24601);
除非它知道 someFunction 不會導致上述函式呼叫被遞回呼叫并比較傳遞給嵌套呼叫的指標的地址。從 C18 開始,允許編譯器生成與后一種形式一樣高效的代碼的唯一方法是程式員定義一個命名常量物件并傳遞其地址,如該示例所示。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/410348.html
標籤:
