У вас есть два реальных выбора. Вы можете определить константу с внешней связью, или нет. С внутренней связью у вас будет только копия в каждой единице перевода, которая фактически использует константу, при условии, что оптимизация включена.
Внутренняя связь:
// a.h
const double AI_LIKE_COOKIES = 5.0;
Внешняя связь:
// a.h
extern const double AI_LIKE_COOKIES;
// a.c
const double AI_LIKE_COOKIES = 5.0;
Однако, Вы можете спросить: "А как насчет встроенных констант?" К сожалению, операнды с плавающей точкой не могут быть встроены. Всякий раз, когда вы используете постоянную с плавающей запятой в функции, это значение сохраняется как постоянная в памяти. Рассмотрим две функции:
// In func1.c
double func1(double x) { return x + 5.7; }
// In func2.c
double func2(double x) { return x * 5.7; }
По всей вероятности, оба файла будут где-то содержать постоянную 5.7, которая затем загружается из памяти. Оптимизация действительно не выполняется *. Вы получаете две копии 5.7, как если бы вы сделали это:
extern const double CONSTANT_1, CONSTANT_2;
const double CONSTANT_1 = 5.7;
const double CONSTANT_2 = 5.7;
double func1(double x) { return x + CONSTANT_1; }
double func2(double x) { return x * CONSTANT_2; }
* Примечание: В некоторых системах вы получаете меньший код, если знаете, что константа будет связана с одним и тем же двоичным изображением, а не загружена из библиотеки.
Рекомендация: Используйте extern
в заголовочном файле и определите константу в одной единице перевода. Скорее всего, код не будет медленнее и не позволит оптимизировать время соединения, это единственный хороший способ убедиться, что в конечном продукте окажется только одна копия.
Звучит как суета на протяжении восьми байт, хотя ...
Ассемблер:
Вот функция:
double func(double x)
{
return x + 5.0;
}
Вот ассемблер, на x86_64:
_Z4funcd:
.LFB0:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
addsd .LC0(%rip), %xmm0
ret
.cfi_endproc
.LFE0:
.size _Z4funcd, .-_Z4funcd
.section .rodata.cst8,"aM",@progbits,8
.align 8
.LC0:
.long 0
.long 1075052544
Обратите внимание на символ LC0
, который является константой, содержащей значение 5.0. Встраивание ничего не сделало, но сделало символ невидимым, чтобы он не отображался в nm
. Вы по-прежнему получаете копию константы, сидящей в каждой единице перевода, которая использует константу.