在特定情况下,指针删除和铸造之间的关系不清楚

Unclear relationship between pointer dereferencing and casting in a specific scenario

本文关键字:之间 关系 不清楚 指针 删除 在特定情况下      更新时间:2023-10-16

我有以下CPP函数:

u_long stringIpV4ToBinary(const char * ipv4)
{
    u_long * buff[1];
    int ret = InetPton(AF_INET, ipv4, &buff);
    if (ret == -1) return 1;
    if (ret == 0) return 1; // more handling needs to be added
// return ntohl(*buff[0]);           // crash, no warning
// return ntohl((*buff)[0]);         // same meaning above (??) crash, no warning
// return ntohl(**buff);             // crash, no warning
// return ntohl(*(buff[0]));         // crash, no warning
// return ntohl(*(u_long*)buff[0]);  // crash, no warning
// return ntohl((u_long)buff[0]);    // works, but produces warnings:: 'type cast': truncation from 'u_long *' to 'u_long'
// return ntohl(*(u_long*)&buff);    // works
// return ntohl(*(u_long*)&buff[0]); // works
// return ntohl(*(u_long*)buff[0]);  // crash, no warning
// return ntohl(*(u_long*)buff);     // works
}

我花了一些时间试图提取我需要传递给ntohl()的buff值(因此您可以忽略前几行)。我正在玩*buff[0] *buff和其他人,因为我意识到我需要施放数组的第一个元素的值( &buff[0]buff&buff)。

问题:为什么我需要将检索到的值投放到(u_long*),然后授予指针?@ @ Runtime中持有buff[0]中持有的值是u_long *类型的A模棱两可或不清楚吗?我的期望是 ntohl(**buff)-(buff是数组名称,它腐烂到指针中,并且由于数组是u_long pointers本身的),双重删除应该足够。

您的 buff定义为 pointer 的数组(尺寸1) u_long。因此,InetPton将所得的IP地址直接存储在此指针变量中。然后,您会崩溃,因为此IP地址被解释为内存地址并重新引用。

buff应定义为简单的u_long,其地址传递给InetPton

u_long buff;
int ret = InetPton(AF_INET, ipv4, &buff);

然后您可以这样做:

return ntohl(buff);

在此改进,如果第一个参数的值为 AF_INET

,则为MSDN页面说明以下内容。
INT WSAAPI InetPton(
  _In_  INT     Family,
  _In_  PCTSTR pszAddrString,
  _Out_ PVOID  pAddrBuf
);

...

指定此参数时,pszAddrString参数必须 指向IPv4地址和pAddrBuf的文本表示形式 参数返回指向IN_ADDR结构的指针 IPv4地址。

因此,您应该在第三个参数中传递IN_ADDR的地址:

IN_ADDR addr;
int ret = InetPton(AF_INET, ipv4, &addr);
...
return ntohl(addr.S_addr);

编辑:

扩展了为什么演员会有所作为,事实证明它没有。有所不同的是间接水平和您退出多少次。

传递给ntohl的参数不需要铸造。

解析IPv4字符串地址时InetPton只需要一个可以写4个字节的内存中的地址。

u_long addr; // 4 bytes on Windows
int ret = InetPton(AF_INET, ipv4, &addr);
if (ret == -1) return 1;
if (ret == 0) return 1; // more handling needs to be added
return ntohl(addr);

理想情况下,您将使用IN_ADDR类型,但是如果您只关心Windows,则可以直接使用基于long的类型。

在需要将数据存储在上述变量中时,将堆栈上的变量声明为指针(*)是没有道理的,这是C101。

InetPton的呼叫将32位IPv4地址写入buff中的第一个u_long *

双重主管的所有变体都将该值对待,就像是指指针一样。不是,这就是为什么他们崩溃的原因。

工作的人只能执行单个解雇并将结果视为长时间,这就是它们工作的原因。(尽管我怀疑其中许多人实际上具有未指定或未定义的行为,因为您对该值是指针还是整数非常狂热。)

如果将buff声明为IN_ADDR,您的代码可能更简单且明显正确。