При выполнении арифметических действий с указателем с помощью offsetof
является ли хорошо определенным поведением получение адреса структуры, добавление к ней смещения члена, а затем разыменование этого адреса для перехода к базовому члену?
Рассмотрим следующий пример:
#include <stddef.h>
#include <stdio.h>
typedef struct {
const char* a;
const char* b;
} A;
int main() {
A test[3] = {
{.a = "Hello", .b = "there."},
{.a = "How are", .b = "you?"},
{.a = "I\'m", .b = "fine."}};
for (size_t i = 0; i < 3; ++i) {
char* ptr = (char*) &test[i];
ptr += offsetof(A, b);
printf("%s\n", *(char**)ptr);
}
}
Это должно печатать «там», «ты?» и "хорошо". в трех последовательных строках, что в настоящее время выполняется как с clang, так и с gcc, поскольку вы можете проверить себя на wandbox. Однако я не уверен, нарушают ли какие-либо из этих приведения указателей и арифметические действия какое-либо правило, которое может привести к тому, что поведение станет неопределенным.
offsetof
использовании. - person Ben Steffan   schedule 02.10.2017test[i].b
будет выполнять ту же арифметику указателя, что и необходимо, но гарантирует правильное поведение, в то время как взлом указателя - нет. И поскольку это распространенный случай, именно на нем разработчики компиляторов сосредоточат внимание на оптимизации, в то время как у них могут быть не столь эффективно оптимизированные хаки с указателями. Можно представить себе случай, когдаtest[i].b
компилируется в одну инструкциюload
, а ручная арифметика выполняется в виде отдельных шагов, за которыми следуетload
. - person zstewart   schedule 03.10.2017offsetof
или компилятора, который фактически обрабатывает Common Initial Sequence гарантирует удобство использования. - person supercat   schedule 04.10.2017