| 
			| 
					
						| sh_m 
								Гость
 | 
								|  | «  : 18-08-2003 07:34 »  |  | 
 
 Есть ли в Си какой-нибудь оператор, который выдает значение смещения переменной внутри структуры?
 Например:
 struct A
 {
 int p1;
 char b;
 int  p2;
 float val;
 char m;
 }
 
 Как мне программно узнать, что val находится по смещению 9?
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| SlavaI 
								Главный специалист    Offline | 
								|  | « Ответ #1 : 18-08-2003 07:46 »  |  | 
 
 Он и по смещению 12 может быть из-за необходимости выравнивания у процессора. 
 Узнавай смещение вот так
 
 int offset = (int)(&((struct A*)0)->val);
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| RXL | 
								|  | « Ответ #2 : 18-08-2003 07:55 »  |  | 
 
 Вот примерчик из исходников linux-а : /* linux/list.h */
 
 #define list_entry)ptr,type,member: ))type*:))char*:)ptr:-)unsigned long:)&))type*:0:->member:::
 
По адресу (ptr) члена структуры (member) и ее типу (type) находит адрес начала структуры. Поняв как это делается, нетрудно сделать и обратное вычисление. |  
						| 
								|  |  
								|  |  Записан | 
 
 ... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |  |  | 
	| 
			| 
					
						| RXL | 
								|  | « Ответ #3 : 18-08-2003 08:02 »  |  | 
 
 Вот и SlavaI меня опередил с ответом   Могу только порекомендовать для удобства и снижения вероятности ошибки сделать макрос: #define member_offset)ptr,type,member:  ))int:)&))type*:0:->member::
 
 |  
						| 
								|  |  
								|  |  Записан | 
 
 ... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |  |  | 
	| 
			| 
					
						| SlavaI 
								Главный специалист    Offline | 
								|  | « Ответ #4 : 18-08-2003 08:08 »  |  | 
 
 Токо так сделай макрос #define member_offset)type,member:  ))int:)&))type*:0:->member::
 
Член ptr не нужен. А у нас в винде тоже похожий макрос есть // begin_winnt begin_ntminiport
 //
 // Calculate the byte offset of a field in a structure of type type.
 //
 
 #define FIELD_OFFSET)type, field:    ))LONG:)LONG_PTR:&)))type *:0:->field::
 
 //
 // Calculate the address of the base of the structure given its type, and an
 // address of a field within the structure.
 //
 
 #define CONTAINING_RECORD)address, type, field: ))type *:) \
 )PCHAR:)address: - \
 )ULONG_PTR:)&))type *:0:->field:::
 
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| sh_m 
								Гость
 | 
								|  | « Ответ #5 : 18-08-2003 08:26 »  |  | 
 
 Спасибо за ответы! Только что проверил - работает! Он и по смещению 12 может быть из-за необходимости выравнивания у процессора. 
 Я с этим даже сталкивался. Проблема чаще всего всплывает при необходимости обмена данными по tcp  между процессами, скомпилированными в разных операционках и соответственно разными средствами с разными опциями по-умолчанию. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| RXL | 
								|  | « Ответ #6 : 18-08-2003 08:32 »  |  | 
 
 Член ptr не нужен.
 
 Поторопился немного...   |  
						| 
								|  |  
								|  |  Записан | 
 
 ... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |  |  | 
	| 
			| 
					
						| SlavaI 
								Главный специалист    Offline | 
								|  | « Ответ #7 : 18-08-2003 08:44 »  |  | 
 
 Я с этим даже сталкивался. Проблема чаще всего всплывает при необходимости обмена данными по tcp между процессами, скомпилированными в разных операционках и соответственно разными средствами с разными опциями по-умолчанию.
 
 Чтобы этого безобразия не было надо использовать pragma, у Майкрософтовского есть #pragma pack, чтобы исключить выравнивание. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| sh_m 
								Гость
 | 
								|  | « Ответ #8 : 18-08-2003 09:00 »  |  | 
 
 Чтобы этого безобразия не было надо использовать pragma, у Майкрософтовского есть #pragma pack, чтобы исключить выравнивание.
 У меня проблема была с Borland Builder-ом. Я подправил опцию компилятора (Project->Options...->Advansed Compiler->Data Alignment = Byte) и все стало нормально.  Но #pragma конечно покорректнее. Сейчас глянул Help, в Borland-e такая тоже есть. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #9 : 26-08-2003 15:23 »  |  | 
 
 я не до конца понимаю вот что: Узнавай смещение вот так
 int offset = (int)(&((struct A*)0)->val);
 
  :arrow: что возвращает выражение        (struct A*)0   :arrow: будет ли строке    int offset = (int)(&((struct A*)0)->val)    эквивалентно следующее: A  a1;
 int offset = )int:)&)a1->val:: - )int:)&a1:
 
 |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Yess 
								Гость
 | 
								|  | « Ответ #10 : 27-08-2003 03:26 »  |  | 
 
 В страндартной библиотеке есть макрос offsetof (stddef.h), который определен как #define offsetof(s,m)   (size_t)&(((s *)0)->m). Теперь по шагам:
 1. ((s *)0) - разыменование null-указателя.
 2. &(((s *)0)->m) - здесь будет получен адрес члена m
 3. (size_t)&(((s *)0)->m) - приведение адреса к size_t.
 Это эквиваленто следующему
 
 struct S
 {
 int a;
 int b;
 int c;
 };
 
 int main()
 {
 S* p = (S*)0; // здесь p==0x00000000
 size_t* b =(size_t*)&(p->b); // здесь b==0x00000004.
 // После преобразования к (size_t) получаем 4, - это и есть смещение b внутри S
 
 return 0;
 }
 
 И замечания:
 1. Стандартная библиотека имеет право разыменовывать null-указатель в своей реализации. Ты сам в своей программе - нет, т.к. это не является легальным С++.
 
 2. offsetof может применяться только для POD-типов.
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| SlavaI 
								Главный специалист    Offline | 
								|  | « Ответ #11 : 27-08-2003 05:14 »  |  | 
 
 Стандартная библиотека имеет право разыменовывать null-указатель в своей реализации
 
 Что то я не понял утверждения. Ты что имеешь в виду вот это-  *((class A*)NULL) так это ошибка, если память по нулевому адресу не выделена, а в большинстве ОС так сделано специально. Что-то я сомневаюсь в наличии в стандарте такого скользкого пункта. Какой номер у него? |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Yess 
								Гость
 | 
								|  | « Ответ #12 : 27-08-2003 05:24 »  |  | 
 
 Я говорю не про Стандарт, а про конкретную реализацию стандартной библиотеки под конкретную платформу. Т. е. для этой платформы точно известно, что в результате разыменования null-указателя получится 0x00000000. Но это может не выполнятся для других платформ. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| SlavaI 
								Главный специалист    Offline | 
								|  | « Ответ #13 : 27-08-2003 06:03 »  |  | 
 
 Т. е. для этой платформы точно известно, что в результате разыменования null-указателя получится 0x00000000.
 
 А что за платформа такая? Какая-то неестественная, стандартно разработчики операционок память по нулевому адресу не выделяют, специально чтобы ловить ошибки типа разименования нулевого указателя. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Yess 
								Гость
 | 
								|  | « Ответ #14 :  27-08-2003 06:13 »   |  | 
 
 1. null-pointer гарантированно не является указателем ни на какой объект(пунк Стандарта сказать не могу - под рукой нет).
 2. При обращении к экземпляру объекта, полученного в результате разыменования null-указателя возникает undefined behavior (точно не помню, вроде пункт 1.9 и 8.3.2)
 
 3.Реализация стандартной библиотеки имеет право опираться на любые implementation defined особенности платформы, в том числе на определенность "неопределенного поведения". При этом, разумеется, требуется, чтобы поведение оставалось определенным для всех легальных применений данной конструкции. Для вышеприведенной реализации 'offsetof' это условие выполняется.
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	|  |