Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Visual C++ 2010 - баг выравнивания структур? 
:(
    Опции темы
0xDEAD
Дата 5.4.2012, 15:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



Добрый день.

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

Код

#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, выдает баг.
Это баг, или я что-то не так делаю?

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

Это сообщение отредактировал(а) 0xDEAD - 6.4.2012, 23:57

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  test.rar 2,78 Kb
PM MAIL   Вверх
Earnest
Дата 5.4.2012, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



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


--------------------
...
PM   Вверх
0xDEAD
Дата 6.4.2012, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



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

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

Похоже на баг.
PM MAIL   Вверх
alexvs11
Дата 6.4.2012, 17:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


hell is here
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 21.8.2010

Репутация: нет
Всего: 10



0xDEAD, вы все же перечитайте пост Earnest, про выравнивание структур
PM MAIL   Вверх
Earnest
Дата 6.4.2012, 17:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



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


--------------------
...
PM   Вверх
alexvs11
Дата 6.4.2012, 17:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


hell is here
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 21.8.2010

Репутация: нет
Всего: 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. 

PM MAIL   Вверх
0xDEAD
Дата 7.4.2012, 00:00 (ссылка)    | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



Цитата(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 выдает баг.
PM MAIL   Вверх
volatile
Дата 7.4.2012, 01:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 4
Всего: 85



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

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


Дело в том что выравнивание по умолчанию структур в 32 и 64 разрядных режимах разные.
напишите перед структурой:
#pragma pack(1)
если проблема повоторится, тогда и будет говорить о баге...
PM MAIL   Вверх
0xDEAD
Дата 7.4.2012, 12:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



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

В любом случае, я изминил в своем коде sizeof на offsetof, и теперь все работает.
PM MAIL   Вверх
alexvs11
Дата 7.4.2012, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


hell is here
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 21.8.2010

Репутация: нет
Всего: 10



0xDEAD, что все? зачем это?
PM MAIL   Вверх
0xDEAD
Дата 7.4.2012, 13:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



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);

PM MAIL   Вверх
alexvs11
Дата 7.4.2012, 16:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


hell is here
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 21.8.2010

Репутация: нет
Всего: 10



0xDEAD, а причем первый вопрос? чтото непойму
PM MAIL   Вверх
0xDEAD
Дата 7.4.2012, 18:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



sizeof(STRU) дает не верный результат, по этому "hello" пишется не туда, а printf пичатает мусор.
PM MAIL   Вверх
Dem_max
Дата 7.4.2012, 19:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 1
Всего: 39



Цитата

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

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

Цитата

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

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


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0631 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.