Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Visual C++ 2010 - баг выравнивания структур?


Автор: 0xDEAD 5.4.2012, 15:08
Добрый день.

Есть такой код:

Код

#include <windows.h>
#include <stddef.h>

typedef struct {
    void *a;
    int  b[27];
    char c[0];
} STRU;

void main()
{
    if(sizeof(STRU) == offsetof(STRU, c))
        MessageBox(NULL, "OK", "", MB_OK);
    else
        MessageBox(NULL, "Bug?", "", MB_OK);

    ExitProcess(0);
}


Если компилирую под 32 бит, выдает ОК, если под 64, выдает баг.
Это баг, или я что-то не так делаю?

Проект в аттаче.

Автор: Earnest 5.4.2012, 16:40
Почему сразу баг-то? Выравнивание - вещь гвоздями не прибитая. Ее можно установить как для проекта, так и для любой части кода.
Видимо, в установках проекта разных конфигураций оно разное. 
Чтобы гарантировать устойчивое выравнивание для каких-то структур, используй #pragma pack (push, N) (вместо N - сколько надо).

Автор: 0xDEAD 6.4.2012, 16:30
Посмотри еще раз на код.
Одна и та же структура, одна и та же платформа, два разных метода добывания размера дают разный результат.

Более того, если, например, изменить int  b[27]; на int  b[3];, или убрать void *a;, все будет правильно работать.

Похоже на баг.

Автор: alexvs11 6.4.2012, 17:01
0xDEAD, вы все же перечитайте пост Earnest, про выравнивание структур

Автор: Earnest 6.4.2012, 17:04
Интересно было бы посмотреть на выравнивание (относительные адреса) каждого члена... т.е. offsetof
А может это у компилятора по поводу поля нулевого размера особое мнение?  "Метод добывания размера" путем взятия адреса "левого" поля как-то сомнительно выглядит. Хотя вроде бы с точки зрения старого доброго С все ok. Может это UB а не баг?

Автор: alexvs11 6.4.2012, 17:10
Цитата(0xDEAD @  5.4.2012,  15:08 Найти цитируемый пост)
b = (char *)&stru.c[0] - (char *)&stru;

это строка нарушает стандарт
по стандарту можно вычитать указатели только
1) одного типа
2) являющиеся элементами одного массива
результатом вычитания будет ptrdiff_t
все остальное UB

Цитата

When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object; the result is the difference of the
subscripts of the two array elements. The size of the result is implementation-defined,
and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header.
If the result is not representable in an object of that type, the behavior is undefined. 

Автор: 0xDEAD 7.4.2012, 00:00
Цитата(alexvs11 @  6.4.2012,  17:10 Найти цитируемый пост)
b = (char *)&stru.c[0] - (char *)&stru;

это строка нарушает стандарт

Может и так, но как раз она правильно работает, в отличие от sizeof.

Я упростил пример в первом сообщении, используя offsetof:
Код

    if(sizeof(STRU) == offsetof(STRU, c))
        /*OK*/;
    else
        /*Bug?*/;


Результат тот же: под 32 бит выдает ОК, под 64 выдает баг.

Автор: volatile 7.4.2012, 01:03
Цитата(0xDEAD @  7.4.2012,  00:00 Найти цитируемый пост)
под 64 выдает баг. 

0xDEAD, 
вот это, внимательно читаем.
Цитата(Earnest @  5.4.2012,  16:40 Найти цитируемый пост)
используй #pragma pack (push, N)


Дело в том что выравнивание по умолчанию структур в 32 и 64 разрядных режимах разные.
напишите перед структурой:
#pragma pack(1)
если проблема повоторится, тогда и будет говорить о баге...

Автор: 0xDEAD 7.4.2012, 12:25
volatile, внимательно читаем код в первом посте.
При чем тут pragma pack?
Я не сравниваю 32 битный размер с 64 битным, а 32 с 32, и 64 с 64, двумя разными методами.

В любом случае, я изминил в своем коде sizeof на offsetof, и теперь все работает.

Автор: alexvs11 7.4.2012, 13:01
0xDEAD, что все? зачем это?

Автор: 0xDEAD 7.4.2012, 13:10
alexvs11, примерно так:

Код

typedef struct {
    void *a;
    int  b[27];
    char c[0];
} STRU;

STRU s;
char *buff = malloc(/*...*/);

s.a = x;
for(i=0; i<27; i++)
    s.b[i] = y;

CopyMemory(buff, &s, sizeof(STRU));
CopyMemory(buff+sizeof(STRU), "hello", sizeof("hello"));

printf("%s", ((STRU *)buff)->c);

Автор: alexvs11 7.4.2012, 16:08
0xDEAD, а причем первый вопрос? чтото непойму

Автор: 0xDEAD 7.4.2012, 18:08
sizeof(STRU) дает не верный результат, по этому "hello" пишется не туда, а printf пичатает мусор.

Автор: Dem_max 7.4.2012, 19:01
Цитата

sizeof(STRU) дает не верный результат

и сколько размер sizeof(STRU) из 64 битной программы  ?

Цитата

по этому "hello" пишется не туда, а printf пичатает мусор.

Логично, потому что пишешь не туда, поэтому и printf пичатает мусор.
Бага тут нет.  

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)