Могут ли приведения быть более производительными, чем помеченные союзы? - PullRequest
0 голосов
/ 02 июня 2019

Я проектирую классическую виртуальную машину, которая будет работать на каком-то типичном значении с переключением типов - теперь представлено помеченным объединением:

typedef struct val {
    val_type type;
    union {
        int            i;
        unsigned int   u;
        double         f;
        str *        str;
        vec *        vec;
        map *        map;
    };
} val;

Я нашел много литературы об этом в Интернете и пришел к выводу, что это довольно ортодоксальный подход к проблеме. Однако мне интересно, можно ли улучшить производительность с помощью такого подхода:

typedef struct val_int {
    val_type type;
    int i;
};

typedef struct val_str {
    val_type type;
    char * buffer;
    size_t length;
    size_t capacity;
};

typedef struct val_vec {
    val_type type;
    val_type ** members; // <-- access member by cast
    size_t length;
    size_t capacity;
};

Здесь я рассуждаю о том, что существует компромисс между стоимостью дополнительной косвенной ссылки для доступа к примитивным типам (а также необходимостью выполнения отдельных распределений - возможно, с помощью объединения), удерживаемой в отношении памяти, сохраненной в коллекциях, таких как val_vec, уменьшив наполовину размер указателя, который он представляет в данный момент. Я знаю, что простым ответом здесь будет «измерить его», но у меня возникают проблемы с созданием адекватно репрезентативной модели, которая не является полной реализацией.

Есть ли название для этого второго подхода, и - если предположить, что этим будет управлять осторожно (но не , если он не вызывает неопределенного поведения), существует широко понятый риск того, что я не приходится? Какой подход здесь предпочтительнее?

Кстати, может ли использование гибких элементов массива также использоваться аналогично?

Ответы [ 2 ]

0 голосов
/ 02 июня 2019

В последнем случае вы, вероятно, также определяете

typedef union val {
    val_type           type;
    struct val_int     val_int;
    struct val_str     val_str;
    struct val_vec     val_vec;
} val;

и теперь у вас есть тип объединения, который может содержать любой тип значения. Действительно, это был обычный способ сделать это до появления анонимных союзов и структур. Когда у вас есть объект, который, как вы знаете, будет только val_int, вы можете сохранить пару байтов памяти, просто выделив val_int и приведя его адрес к val *.

0 голосов
/ 02 июня 2019

Я полагаю, что существует компромисс между стоимостью дополнительной косвенной ссылки для доступа к примитивным типам

Преждевременная оптимизация редко стоит вашего ценноговремя кодированияЛюбое изменение здесь в лучшем случае линейно.6,001 против 1/2 дюжины других.

Так или иначе, может быть лучше в выбранных вами обстоятельствах, но чем больше информации предоставлено компилятору, тем больше вероятность, что он будет оптимизирован лучше, чем вы можете здесь.

Код для ясности, который обычно избегает приведений.

Альтернатива не содержит подробностей и, вероятно, проблематична, учитывая обычные неверные предположения: void * или val_type * - универсальный указатель, указатели в FP хорошо преобразуются в другие указатели, приведенные выравнивания -достаточно для других типов, сглаживание не является проблемой.

...