C - Что делает * (long *) (host-> h_addr); делать? - PullRequest
0 голосов
/ 11 сентября 2018

Я нашел следующий код в этом примере:

addr.sin_addr.s_addr = *(long *)(host->h_addr);

h_addr - это указатель char, а host - указатель на структуру типа hostent. addr - это структура типа sockaddr_in, а sin_addr - это структура типа in_addr. s_addr является uint32.

Большую часть этой информации можно найти здесь: http://man7.org/linux/man-pages/man7/ip.7.html

Я почти уверен, что (long) долго сбрасывает символ, но я не знаю, что делают дополнительные звездочки, особенно потому, что s_addr не является указателем.

Может кто-нибудь объяснить, что здесь происходит?

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

(long *)(host->h_addr) означает интерпретировать host->h_addr как указатель на long.Это не очень переносимо, но, по-видимому, long имеет длину 32 бита в системе, для которой было написано.

Дополнительная звездочка в *(...) разыменовывает то, что теперь является long для назначения.Это эффективно копирует все четыре байта исходного массива char в одно значение long addr.sin_addr.s_addr.Сравните с (long)(*host->h_addr), который будет копировать только первый элемент char.

Эта техника крайне непереносима.Предполагается как размер, так и порядковый номер типа long.У вас может возникнуть искушение взять подсказку из того факта, что s_addr является uint32, и сделать:

addr.sin_addr.s_addr = *(uint32_t *)(host->h_addr);

Это не намного лучше, потому что порядок байтов все еще подорван.Кроме того, uint32_t гарантированно содержит не менее 32 бит.Это может быть любое большее число битов, которое вызовет неопределенное поведение, когда вы попытаетесь прочитать нераспределенную память с копией (представьте, что вы копируете 32-битные данные char как 64-битное целое число).

Таместь два варианта:

Если ваш массив char уже находится в правильном порядке байтов (т. е. вам все равно, если h_addr[0] представляет старший или младший байт локального uint32_t), используйте memcpy:

memcpy(&(addr.sin_addr.s_addr), host->h_addr, 4);

Это, вероятно, тот подход, который вам нужен.Если, с другой стороны, вы хотите, чтобы h_addr[0] всегда заканчивался старшим байтом, вам необходимо соблюдать порядковый номер вашей системы:

addr.sin_addr.s_addr = (host->h_addr[0] << 24) + (host->h_addr[1] << 16) + (host->h_addr[2] << 8) + (host->h_addr[3]);

Вероятно, должны быть некоторые приведения к uint32_tпо пути туда.

0 голосов
/ 11 сентября 2018

Я бы прочитал так: «addr.sin_addr.s_addr равен объекту приведения к long указателю host-> h_addr», или, более кратко, «addr.sin_addr.s_addr равен long, указанному дляпо host-> h_addr ".host->h_addr, по-видимому, является указателем на что-то отличное от long - здесь этот адрес обрабатывается как указатель на long, а long, на который он указывает, присваивается addr.sin_addr.s_addr.

HTH.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...