1. Java / Говнокод #15809

    +64

    1. 1
    short someShort = (short) (someBoolean ? 15 : 42);

    такая удобная Java

    Запостил: evg_ever, 21 Апреля 2014

    Комментарии (118) RSS

    • а нафига ваще short?
      short побъери!
      Ответить
      • Спроси у разработчиков Apache POI, у них крайне часто он используется в параметрах методов. https://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/Workbook.html#getFontAt(short) Видимо, сокращение ОДЗ аргумента
        Ответить
        • скорее всего экономия памяти.
          под short надо 2 байта, а под int 4.
          Ответить
          • Выравнивание чуть ли не на 16 байт.
            Ответить
            • выравнивание стэка как правило равно размеру регистра, так как это то что на стэк записывается. поэтому все (целочисленые) переменные которые по стэку передаются, выравниваются на размер регистра. (но с другой стороны жаба не обязана поддерживать соглашения ABI.)

              но на локальные переменные это правило не распространяется. локальные переменные как правило выравнены по размеру своего типа, подобно как в структурах.

              выравнивание стэка на 16 байт это ты скорее всего путаешь с выравниванием стэк фрэйма: размер параметров функции (как и суммарный размер локальных переменных) часто выравнивается на 16/32 байт. для того что бы cache line alignment был.
              Ответить
              • В гцц видел дырку между аргументами функции int и short размером в 16 байт. Если 2 инта то дырки нет.
                Ответить
                • А если 2 шорта? Скорее всего аргументы на стеке тупо догоняются до интов.
                  Ответить
                  • В cdecl - да, дополняются.
                    Ответить
                    • в контексте нужно различать два разных "на стеке": "аргументы функции на стеке" и "локальные переменные на стеке." до размера регистров догоняются только аргументы. и догоняются они только внутренне: с точки зрения программы, они все равно шорты/чары.
                      Ответить
                • странно. я много стеков ковырял, включая гцц, но больших дырок никогда не видел. короткий тест на линухе.64 дырок тоже не показал.
                  Ответить
                  • http://ideone.com/ZW2ZUZ
                    Ответить
                    • FreeBSD clang 3.3 (x86_64) - 2
                      FreeBSD clang 3.3 (x86_64 -m32) - КРОВЬ КИШКИ skipping incompatible /usr/lib/libc++.so.1 when searching for /usr/lib/libc++.so.1 (я не ставил пакета совместимости с x86, увы)
                      Linux gcc 4.7.3 (x86_64) - 4
                      Linux gcc 4.7.3 (x86_64 -m32) - 20

                      Немного переписал пример, и посмотрел, что происходит в асме:
                      void shit(int a, short b) {
                        std::printf("%p %p %llu\n",
                          &a,
                          &b,
                          (unsigned long long)((uintptr_t)&a - (uintptr_t)&b)
                        );
                      }

                      sub esp, 0x3c
                      mov eax, dword ptr [esp+0x44] ; второй аргумент, ибо 0x44 - 0x3c = 8 (пропускаем адрес возврата и первый аргумент)
                      mov word ptr [esp+0x2c], ax ; кладем этот short в локальную переменную на стеке
                      lea eax, [esp+0x2c] ; адрес локальной переменной
                      lea edx, [esp+0x40] ; адрес первого аргумента на стеке
                      sub, edx, eax
                      mov dword ptr [esp+0x10], edx ; это будет тот самый последний аргумент printf, то есть разница указателей

                      Короче, для инта в качестве адреса он берет адрес параметра на стеке. Short же почему то перекладывает в локальную переменную нового фрейма, и берет уже её адрес.
                      Ответить
                      • Linux clang 3.3 (x86_64) - 2
                        Linux clang 3.3 (x86_64 -m32) - 2

                        Во втором случае он решил не рисковать, и переложил обе переменные в новый фрейм. (В первом, очевидно, тоже, ибо в amd64 аргументы через регистры передаются, так что выгружать на стек в любом случае надо явно)
                        Ответить
                    • http://ideone.com/ExQbuZ

                      ХЕЗ. какая-то оптимизация того как аргументы на стек ложатся.

                      и 32 битного ABI под рукой нет что бы посмотреть в детали.
                      Ответить
                      • cout << ((sizeof(long) == 8)+1)*32 << "bit arch" << endl;

                        Ололо, на говнокод.ру! Wait... oh shi~.
                        Ответить
                      • Это как бы доказывает, что при использовании переменных разной длины стек хитро пидорасит. Если можно инт, юзай инт.
                        Ответить
              • в java есть структуры? О.о
                Ответить
              • >но на локальные переменные это правило не распространяется. локальные переменные как правило выравнены по размеру своего типа, подобно как в структурах.
                Почему?
                Ответить
                • аргументы: где-то читал что это старая конвенция из С, и что-то там ломается если делать по другому. деталей сам не знаю. (вроде бы как для va_args это и не надо - но в ихних сырцах и находил что на стеке целые числа до int/long расшираются.)

                  локальные переменные: а почему бы и нет? в ABI так написано.
                  Ответить
                • > локальные переменные как правило выравнены по размеру своего типа, подобно как в структурах
                  Патамушта эти ваши ARM'ы в андроидах и айфонах и прочие не x86 не любят криво выровненные данные.
                  Ответить
                  • Но отдельные поля как раз плохо выровняны...
                    Ответить
                    • Да ну? Двухбайтовые на 2 байта, четырехбайтовые на 4 и т.п. Разве не так?
                      Ответить
                      • На 2 байта - это с точки зрения проца невыровняно.
                        Ответить
                        • Двухбайтовое на 2 байта с точки зрения проца как раз выровнено. Четырехбайтовое на 2 - нет.
                          Ответить
                    • это просто нереально!
                      http://java-performance.info/overview-of-memory-saving-techniques-java/
                      byte, boolean 1 byte
                      short, char 2 bytes
                      int, float 4 bytes
                      long, double 8 bytes
                      Byte, Boolean 16 bytes
                      Short, Character 16 bytes
                      Integer, Float 16 bytes
                      Long, Double 24 bytes


                      я кстати может чего-то не понимаю, но нахера 16 байт под булевой тип? или я хрень какую-то нашел? :)
                      в шарпике
                      A Boolean value occupies one byte of memory. The byte's low-order bit is used to represent its value. A value of 1 represents true; a value of 0 represents false.
                      Ответить
                      • >но нахера 16 байт под булевой тип?
                        Шура, а сколько вообще инстансов типа Boolean вам нужно для счастья?
                        Аlignment.
                        >boolean 1 byte
                        >A Boolean value occupies one byte of memory. The byte's low-order bit is used to represent its value.
                        Это пиздёж. Зависит строго от JVM и как boolean выглядит, если массив - будут биты, в классе надо доравнять до 8-байтной границы.
                        Ответить
                        • > Это пиздёж.
                          Он о шарпе же. Внимательней :)
                          Ответить
                          • >http://java-performance.info/
                            >boolean 1 byte
                            Ответить
                          • >Он о шарпе же.
                            Тоже пиздёж.
                            A bool is actually only 1 byte, but alignment may cause 4 bytes to be used on a 32-bit platform, or even 8 bytes on a 64-bit platform. For example, the Nullable<bool> (aka bool?) type uses a full 32 or 64 bits—depending on platform—even though it's comprised of just two bools. EDIT: As pointed out by Jon Skeet, padding for alignment isn't always present. As an example, an array of Nullable<bool>s takes only 2 bytes per object instead of 4 or 8.
                            http://stackoverflow.com/questions/294905/why-in-net-system-boolean-takes-4-byte

                            The caveat is that when *marshalling* Bools are defined to be 32bits, i.e. 4bytes.

                            bool b=false; Console.WriteLine(System.Runtime.Interop Services.Marshal.SizeOf(b).ToString());
                            it prints 4 byte:)
                            Ответить
                      • 16 байт под объект типа Boolean, а не под примитив
                        Ответить
                        • а чем bool от Boolean отличается?
                          Ответить
                          • возможностью хранить null
                            Ответить
                            • И возможностью юзать его в коллекциях.
                              Ответить
                              • о мой бог, в c# для этого есть bool?, он же Nullable<bool>, который занимает 2 байта, и юзать его можно хоть у черта на рогах.
                                Ответить
                                • Если бы разрабы шарпа не пофиксили самые вопиющие проблемы жабы - их смело можно было бы считать идиотами.
                                  Ответить
                                • > юзать его можно хоть у черта на рогах

                                  потому что там реализация дженериков другая - reified generics.
                                  Ответить
                                • А int? там есть? Как он работает?
                                  Ответить
                                  • конечно есть int, куда без него :) точно так же, как и все остальные.
                                    вообще непонятно, почему примитивы не могут быть в коллекциях
                                    http://www.dotnetperls.com/int
                                    Ответить
                                    • > вообще непонятно, почему примитивы не могут быть в коллекциях

                                      На досуге подумай или почитай, какие подходы можно использовать для реализации дженериков, какие последствия влечёт каждая реализация и какие требования к рантайму она предоватвляет.
                                      Ответить
                                    • Не int, а int? с вопросиком.
                                      Ответить
                                      • > int? с вопросиком.

                                        вопросик это сахар для Nullable<T> где T может быть любым примитивом.
                                        Ответить
                                        • >C# supports two kinds of variable types:
                                          >•Value types
                                          >These are the built-in primitive data types, such as char, int, and float, as well as user-defined types declared with struct.

                                          >•Reference types
                                          >Classes and other complex data types that are constructed from the primitive types. Variables of such types do not contain an instance of the type, but merely a reference to an instance.

                                          >Nullable<T>
                                          >Тип называется допускающим значение NULL, если ему может быть присвоено как непустое значение, так и значение null, означающее, что значение у типа отсутствует. По умолчанию все ссылочные типы, например String, допускающих значение NULL, но все типы значений, например Int32, нет.

                                          >В C# и Visual Basic, в случае тип значения в качестве обнуляемой нотация ? после типа значения. Например, int? в C# в объявляет тип целого числа, можно присвоить null.

                                          [SerializableAttribute]
                                          public struct Nullable<T>
                                          where T : struct

                                          короче говоря, это только для структур сделано.
                                          Ответить
                                          • А как оно реализовано? Так же, как и в яве?
                                            Ответить
                                            • а откуда знаю как на яве :)
                                              http://msdn.microsoft.com/en-us/library/ms228358(v=vs.90).aspx тут есть мануал для java программеров, как с c# соскочить
                                              Ответить
                                              • > мануал для java программеров, как с c# соскочить
                                                Зачем соскакивать с решеток на жабу?!
                                                Ответить
                                            • Ну в смысле Nullable<bool> это объект Nullable со ссылкой на переменную Bool, как в жавке, или объект со свойством bool?
                                              Ответить
                                              • вот определение Nullable
                                                [Serializable, StructLayout(LayoutKind.Sequential)]
                                                public struct Nullable<t> where T : struct
                                                {
                                                    // These 2 fields represent the state
                                                    private Boolean hasValue = false; // Assume null
                                                    internal T value = default(T); // Assume all bits zero
                                                    public Nullable(T value)
                                                    {
                                                        this.value = value;
                                                        this.hasValue = true;
                                                    }
                                                    public Boolean HasValue { get { return hasValue; } }
                                                    public T Value
                                                    {
                                                        get
                                                        {
                                                            if (!hasValue)
                                                            {
                                                                throw new InvalidOperationException(
                                                                "Nullable object must have a value.");
                                                            }
                                                            return value;
                                                        }
                                                    }
                                                    public T GetValueOrDefault() { return value; }
                                                    public T GetValueOrDefault(T defaultValue)
                                                    {
                                                        if (!HasValue) return defaultValue;
                                                        return value;
                                                    }
                                                    public override Boolean Equals(Object other)
                                                    {
                                                        if (!HasValue) return (other == null);
                                                        if (other == null) return false;
                                                        return value.Equals(other);
                                                    }
                                                    public override int GetHashCode()
                                                    {
                                                        if (!HasValue) return 0;
                                                        return value.GetHashCode();
                                                    }
                                                    public override string ToString()
                                                    {
                                                        if (!HasValue) return "";
                                                        return value.ToString();
                                                    }
                                                    public static implicit operator Nullable<t>(T value)
                                                    {
                                                        return new Nullable<t>(value);
                                                    }
                                                    public static explicit operator T(Nullable<t> value)
                                                    {
                                                        return value.Value;
                                                    }
                                                }

                                                думаю ты все и сам поймешь :)
                                                Ответить
                                                • Так это ссылка на обертку к примитивному типу или примитивный тип в самом объекте?
                                                  Ответить
                                                  • структура, хранящая примитив и флажок, никаких обёрток, не тупи
                                                    Ответить
                                                    • Ах, там флаг отдельно для null.

                                                      Роман, что-то знаешь, чего еще не знаю я? Молодец.

                                                      >примитивный тип в самом объекте
                                                      И это шарповые дженерики могут? Респект.
                                                      Ответить
                                                      • > Роман, что-то знаешь, чего еще не знаю я? Молодец.
                                                        да если бы, я на шарпе не пишу. Тут уже 5 раз разжевали, даже сорцы реализации привели.
                                                        Ответить
                                                  • > примитивный тип в самом объекте
                                                    примитивный тип в самом объекте
                                                    Ответить
                          • > а чем bool от Boolean отличается?
                            Ничем. Короткий псевдоним, такой же как string для System.String
                            Ответить
                            • выше писали, что bool не может быть null, и его нельзя в коллеции использовать. кто прав? :)
                              Ответить
                            • ты точно о жабе?
                              Ответить
                      • > но нахера 16 байт под булевой тип
                        Потому что Boolean это объект, блджад! Со всеми вытекающими последствиями. Об него можно даже синхронизироваться при желании.

                        Еще не забывай про 4 байта на ссылку, которая на этот Boolean будет указывать.
                        Ответить
            • выравнивание в 16 байт актуально для объектов, а не для локальных переменных. или я путаю?
              Ответить
              • Для объектов и для стековых фреймов, по идее. Для каждой переменной само собой не нужно.
                Ответить
                • Почему?
                  Ответить
                  • Что почему?

                    Потому что переменные внутри фрейма можно разложить поплотнее, если мы знаем, что фрейм выровнен на 16 байт.
                    Ответить
                    • Кому и для чего нужно выравнивание вообще?
                      Ответить
                      • как минимум производительность, и размер памяти.
                        http://konishchevdmitry.blogspot.fr/2010/01/blog-post.html тут я думаю понятно написано
                        Ответить
                        • Много букв и ни слова о хохлах и ватниках. Ниасилит.
                          Ответить
                        • Я плохо из этого понял, когда и на какую границу надо выравнивать данные.
                          Ответить
                          • Любой вменяемый компилятор сам все сделает как надо, если ему не мешать.

                            Я ж не со зла писал "тебе - не нужно, ты же не байтоёб-сишник какой-нибудь". Оно действительно не нужно, пока не начинаешь заниматься байтоёбством :)
                            Ответить
                            • Я хочу понять, почему компилятор иногда делает так, а иногда этак.
                              Ответить
                            • И оно пригодится и без байтоёбства, когда захочется узнать, почему прога потребляет столько памяти.
                              Ответить
                              • Считать байты - это байтоёбство ;)

                                Да и в 99% случаев на выравниваниях ты много не выиграешь. Ссылки, системная инфа в объектах, кишки коллекций и т.п. всяко больше жрут.
                                Ответить
                                • Кроме массивов.
                                  Ответить
                                  • > Кроме массивов.
                                    Ну а в массив ты сможешь пихать только примитивы и структуры (если мы о шарпе). Примитивы в массивах всегда будут лежать плотно, без выравниваний. Вот и остается только массив мелких структур, в которых ты юзаешь типы разных размеров (например byte и int), тот самый 1% :)

                                    P.S. Кстати, а шарп имеет право менять местами поля в структурах/классах? Если да - то он и тут все сделает за тебя, и выиграть на выравниваниях уже ничего не получится...
                                    Ответить
                                    • А массивов обьектов не бывает?

                                      >тот самый 1% :)
                                      Но это вполне реальный случай
                                      Ответить
                                      • > А массивов обьектов не бывает?
                                        Я не уверен, но это скорее всего будет массив из ссылок на объекты.

                                        > Но это вполне реальный случай
                                        Ну как сказать... Разве что в каких-то вычислительных задачах. Может быть еще в векторной графике.

                                        P.S. Один хрен, больше чем вдвое структура от выравнивания не растянется.
                                        Ответить
                                        • >Я не уверен, но это скорее всего будет массив из ссылок на объекты.

                                          А ну да. Но все же.

                                          Хватит меня отговаривать :) Иди лучше SRP настрой.
                                          Ответить
                                        • >Один хрен, больше чем вдвое структура от выравнивания не растянется.
                                          структуры по сути памяти вообще занимают копейки.
                                          Class version
                                          Size of List: 1 object 512 KB
                                          Size of internal array: 100000 objects 3.8 MB

                                          Struct version
                                          Size of List: 1 object 24 bytes
                                          Size of internal array: 1 object 4.0 MB

                                          про структуры можно тут почитать http://www.dotnetperls.com/struct
                                          Ответить
                                    • вообще-то меняет, но это поведение вроде как можно изменить.
                                      http://msdn.microsoft.com/en-us/magazine/jj863136.aspx
                                      If _data and _initialized are ordinary (that is, non-volatile) fields, the compiler and the processor are allowed to reorder the operations so that Init executes as if it were written like this...

                                      Volatile Fields The C# programming language provides volatile fields that constrain how memory operations can be reordered. The ECMA specification states that volatile fields provide acquire-­release semantics
                                      Ответить
                                      • > http://msdn.microsoft.com/en-us/magazine/jj863136.aspx
                                        Это не совсем то... Я не о порядке записи в поля, а о порядке полей в самой структуре.
                                        Ответить
                                        • ты имеешь в виду порядок, в котором исполняемая среда будет помещать поля объекта в память?
                                          Ответить
                                        • вот тут http://habrahabr.ru/post/114953/ нашел статью, по ручному расположению полей. значит компилятор переставляет их
                                          Ответить
                          • Например, системы типа х8б используют страницы размером 4 Кб, и, если вы попытаетесь зарезервировать 18 Кб памяти, на самом деле будет зарезервировано 20 Кб.
                            как-то так.
                            Ответить
                            • Где нужно выравнивать на сколько?
                              Ответить
                              • что значит где?
                                class cls {
                                int a; //2 bytes
                                DateType b; //8 bytes
                                ..
                                }
                                и так далее
                                в данном случае будет 10 байт, но зарезервирует 12, так как страницы по 4 байта.
                                чет я сам запутался уже, почему до 16 выравнивать надо :)
                                просто надо учитывать, что чем больше объектов ты будешь создавать, тем больше зарезервированных дырок в памяти у тебя будет, и тем больше раз нужно будет запрашивать страницы из памяти
                                Ответить
                                • >чет я сам запутался уже,
                                  То-то и оно. Сам разберись сначала.
                                  Ответить
                                • При чем здесь размер страницы? Размер страницы на x86 - это 4 кибибайта (4096 байт), а не 4 байта.

                                  Выравнивание и padding зависит по большей части от того, что там внутри DateType лежит.

                                  // этим чарам выравнивание не нужно
                                  // так что размер всего будет 10 
                                  class A {
                                      uint16_t a;
                                      struct {
                                          char x[8];
                                      } b;
                                  };
                                  
                                  // здесь sizeof(B) == 16
                                  // потому что uint64_t нужно выравнивание 8
                                  // в памяти будет 2 байта 'a', 6 байт дырка, и 8 байт 'b'
                                  class B {
                                      uint16_t a;
                                      struct {
                                          uint64_t;
                                      } b;
                                  };
                                  Ответить
                                  • почему 6 байт дырка?
                                    Ответить
                                    • uint64_t ты не можешь туда положить, потому что ему нужно выравнивание 8.
                                      Ответить
                                      • То есть, выравнивание должно быть на размер элемента, к которому обращаются, если он влазит в регистр проца?
                                        Ответить
                                        • Ну... примерно так.
                                          Ответить
                                          • т.е. больше чем на битность процессора выравнивать не надо?
                                            Ответить
                                            • Отнюдь. Во всяких SSE есть такой тип, четырехкомпонентные float-векторы, и их стоит по 16 байт (128 бит) выравнивать. Причем доступ по невыровненному адресу будет не просто тормозить, а бросать процессорное исключение.
                                              Ответить
                                              • А с остальными не будет бросать?
                                                Ответить
                                                • Из SSE-инструкций бросают, на самом деле, только MOVAxxx (MOVAPS, MOVAPD, etc.). MOVUxxx (MOVUPS, etc.) не бросают. "Нормальные" невекторные инструкции не бросают никогда, насколько помню.
                                                  Ответить
                                                  • А-а, так это выровненные версии инструкций.
                                                    Ответить
                                • До 16 потому что машинное слово.
                                  Ответить
                      • Тебе - не нужно, ты же не байтоёб-сишник какой-нибудь. Иди дальше питона души.
                        Ответить
                        • и еще структуроеб какой-нибудь :) хотя в Java их нет, но в шарпике на больших объемах спасает.
                          http://www.dotnetperls.com/struct раздел Allocation performance
                          Ответить
                        • показать все, что скрытоТебе тогда вообще ничего не нужно, только консоль из срачла доставать время от времени, чтобы в туалет сходить.
                          Ответить
                          • > консоль из срачла доставать время от времени, чтобы в туалет сходить
                            Нафуя ее доставать? Вывод перенаправил в /dev/null да и все.
                            Ответить
                            • А потом не лопнешь?
                              Ответить
                              • /dev/null ведет вникуда. Вникуде места завались, срать не пересрать.
                                Ответить
                          • > консоль из срачла доставать
                            Почему мне кажется, что этот пациент из старых на гк под другим ником?
                            Ответить
                            • Он может быть и с двачей.
                              Ответить
                              • Не "может быть", а совершенно очевидно с первого поста.
                                И не с двачей, а с сосачей.
                                Ответить
                                • Потому, что консолечку в срачле стали форсить уже после того, как двачи закрылись?
                                  Ответить
                            • >из старых на гк под другим ником?
                              anonimb84a2f6fd141
                              Таким?

                              И кто для пользователя с id>6000 "старые на гк":?
                              Ответить
                              • У тебя 50 не хватает для твоего истинного id.
                                Ответить
          • я short/char индексами/этц пользуюсь изредка как нотацией что типа: не разбегайтесь, работаете с ограниченым ресурсом.
            Ответить

    Добавить комментарий