| 
							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' это условие выполняется. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
						 | 
					 
				 
			 |  
		 
	 | 
	 |