Для забавного применения инициализации двойной скобки см. здесь Массив Dwemthy's в Java .
Отрывок
private static class IndustrialRaverMonkey
extends Creature.Base {{
life = 46;
strength = 35;
charisma = 91;
weapon = 2;
}}
private static class DwarvenAngel
extends Creature.Base {{
life = 540;
strength = 6;
charisma = 144;
weapon = 50;
}}
И теперь, будьте готовы для BattleOfGrottoOfSausageSmells
и & hellip; короткое бекон!
Для маленьких структур (например, точка, реагируйте), передача значением совершенно приемлема. Но, кроме скорости, существует еще одна причина, почему необходимо быть осторожными передающими/возвращающими большими структурами значением: Стековое пространство.
Большое программирование C для встроенных систем, где память в большом почете, и размеры стека могут быть измерены в КБ или даже Байтах... Если Вы передадите или возвратите структуры значением, копии тех структур будут помещены в стек, потенциально вызывая ситуацию, что этот сайт называют в честь...
, Если я вижу приложение, которое, кажется, имеет чрезмерное использование стека, структуры, переданные значением, являются одной из вещей, которые я ищу сначала.
Одна причина не сделать это, которое не было упомянуто, - то, что это может вызвать проблему, где совместимость на уровне двоичных кодов имеет значение.
В зависимости от используемого компилятора, структуры могут быть переданы через стек, или регистры в зависимости от опций/реализации компилятора
Видят: http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
-fpcc-struct-return
-freg-struct-return
, Если два компилятора не соглашаются, вещи, может аварийно завершиться. Само собой разумеется, главные причины не сделать это проиллюстрировано, причины потребления и производительности стека.
Простое решение будет возвратом код ошибки как возвращаемое значение и все остальное в качестве параметра в функции,
, Этот параметр может быть структурой, конечно, но не видит, что какое-то конкретное преимущество передает это значением, просто отправил указатель.
Передающая структура значением опасна, необходимо быть очень осторожными, что является Вами, передача, помнит, что в C нет никакого конструктора копии, если один из параметров структуры будет указателем, то значение указателя будет скопировано, это могло бы очень сбивать с толку и могло бы быть твердо поддержать.
Только для завершения ответа (полный кредит к Roddy) использование стека является другой причиной не, передают структуру значением, верят мне отлаживающий переполнение стека, реальный ЛАВАШ.
Воспроизведение для комментария:
Передающая структура указателем, означающим, что некоторый объект имеет владение на этом объекте и имеет полное знание какой и когда должен быть выпущен. Передающая структура значением создает скрытые ссылки на внутренние данные структуры (указатели на другого структурирует и т.д.) в этом твердо поддержать (возможный, но почему?).
Я думаю, что Ваш вопрос подвел итог вещей вполне прилично.
Еще одно преимущество передающих структур значением состоит в том, что владение памяти является явным. Нет никакого удивления о том, если структура от "кучи", и кто несет ответственность за освобождение его.
Я сказал бы, что передача (not-too-large) структуры значением, и как параметры и как возвращаемые значения, является совершенно законной техникой. Нужно заботиться, конечно, что структура является или типом POD, или семантика копии хорошо определяется.
Обновление: Извините, у меня был свой C++, думая ограничение на. Я вспоминаю время, когда не было законно в C возвратить структуру из функции, но это, вероятно, изменилось с тех пор. Я все еще сказал бы, что это допустимо пока все компиляторы, которые Вы ожидаете использовать, поддерживают практику.
Одна вещь, которую люди здесь забыли упоминать до сих пор (или я пропустил его) состоит в том, что структуры обычно имеют дополнение!
struct {
short a;
char b;
short c;
char d;
}
Каждый символ составляет 1 байт, каждыми короткими составляют 2 байта. Насколько большой структура? Нет, это не 6 байтов. По крайней мере, не в больше наиболее часто используемых системах. В большинстве систем это будет 8. Проблема, выравнивание не является постоянным, это системно-зависимо, таким образом, та же структура будет иметь различное выравнивание и различные размеры в различных системах.
Не только, что дополнение далее съест Ваш стек, оно также добавляет неуверенность в неспособности предсказать дополнение заранее, если Вы не знаете, как Ваша система дополняет, и затем посмотрите на каждую структуру, которую Вы имеете в своем приложении и вычисляете размер для него. Передача указателя берет предсказуемую сумму пространства - нет никакой неуверенности. Размер указателя известен системой, это всегда равно, независимо от того, на что похожа структура, и размеры указателя всегда выбираются способом, что они выровненные и не нуждаются ни в каком дополнении.
Чтобы действительно ответить на этот вопрос, нужно глубоко копнуть в области сборки:
(В следующем примере используется gcc на x86_64. Любой может добавить другой архитектуры, такие как MSVC, ARM и т. д.)
Давайте возьмем наш пример программы:
// foo.c
typedef struct
{
double x, y;
} point;
void give_two_doubles(double * x, double * y)
{
*x = 1.0;
*y = 2.0;
}
point give_point()
{
point a = {1.0, 2.0};
return a;
}
int main()
{
return 0;
}
Скомпилируйте ее с полной оптимизацией
gcc -Wall -O3 foo.c -o foo
Посмотрите на сборку:
objdump -d foo | vim -
Вот что мы получим:
0000000000400480 <give_two_doubles>:
400480: 48 ba 00 00 00 00 00 mov $0x3ff0000000000000,%rdx
400487: 00 f0 3f
40048a: 48 b8 00 00 00 00 00 mov $0x4000000000000000,%rax
400491: 00 00 40
400494: 48 89 17 mov %rdx,(%rdi)
400497: 48 89 06 mov %rax,(%rsi)
40049a: c3 retq
40049b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
00000000004004a0 <give_point>:
4004a0: 66 0f 28 05 28 01 00 movapd 0x128(%rip),%xmm0
4004a7: 00
4004a8: 66 0f 29 44 24 e8 movapd %xmm0,-0x18(%rsp)
4004ae: f2 0f 10 05 12 01 00 movsd 0x112(%rip),%xmm0
4004b5: 00
4004b6: f2 0f 10 4c 24 f0 movsd -0x10(%rsp),%xmm1
4004bc: c3 retq
4004bd: 0f 1f 00 nopl (%rax)
Исключая nopl
pads, give_two_doubles ()
имеет 27 байтов, а give_point ()
- 29 байтов. С другой стороны, give_point ()
дает на одну инструкцию меньше, чем give_two_doubles ()
Что интересно, так это то, что мы заметили, что компилятор смог оптимизировать mov
в более быстрые варианты SSE2 movapd
и movsd
. Кроме того, give_two_doubles ()
фактически перемещает данные в память и из нее, что замедляет работу.
По-видимому, многое из этого может быть неприменимо во встроенных средах (где в настоящее время большую часть времени играет поле для C). Я не мастер сборки, поэтому любые комментарии приветствуются!