草庐IT

c++ - 从 sockaddr * 转换为 sockaddr_in * 增加了所需的对齐方式

coder 2023-06-19 原文

当我处理一些看起来像这样的代码时,编译器会产生这个警告 -

....

for(p = res; p != NULL; p = p->ai_next) {
    void *addr;
    std::string ipVer = "IPv0";

    if(p->ai_family == AF_INET) {
        ipVer                    = "IPv4";
        struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
        addr                     = &(ipv4->sin_addr);
    }

    else {
        ipVer                     = "IPv6";
        struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
        addr                      = &(ipv6->sin6_addr);
    }
....
}

其中 p = resstruct addrinfo 类型,产生警告的类型是 sockaddr_insockaddr_in6。警告来自声明:

  • struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
  • struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;

我只想知道是什么导致这个警告,如果这不是正确的做事方式,我能做什么来纠正它。我可以在这里使用任何 static_cast/dynamic_cast/reinterpret_cast 吗?

确切的警告是 - 从“struct sockaddr *”到“struct sockaddr_in *”的转换将所需的对齐方式从 2 增加到 4

最佳答案

TLDR:此警告并不表示您的代码中存在错误,但您可以通过使用 poper c++ reinterpret_cast(感谢@Kurt Stutsman)来避免它。


解释:

警告原因:

  • sockaddr由一个unsigned short(通常是16位)和一个char数组组成,所以它的对齐要求是2。
  • sockaddr_in 包含(除其他事项外)一个 struct in_addr,它具有 4 的对齐要求,这反过来意味着 sockaddr_in 也必须对齐到 4 字节边界。

因此,将任意 sockaddr* 转换为 sockaddr_in* 会改变对齐要求,并且通过新指针访问对象甚至会违反别名规则和结果在未定义的行为中。

为什么你可以忽略它:

在您的例子中,p->ai_addr 指向的对象很可能是 sockaddr_insockaddr_in6 对象(如通过检查 ai_family) 确定,因此操作是安全的。但是,您的编译器并不知道这一点并会产生警告。

这与使用 static_cast 将指向基类的指针转换为指向派生类的指针本质上是一样的——在一般情况下这是不安全的,但是如果您知道正确的外在的动态类型,它是明确定义的。

解决方案:
我不知道解决这个问题的干净方法(除了抑制警告),这对于 -Weverything 启用的警告并不罕见。您可以将 p->ai_addr 指向的对象逐字节复制到适当类型的对象,但是您可能(很可能)不再使用 addr和以前一样,因为它现在指向一个不同的(例如本地)变量。
-Weverything 无论如何我都不会在我的日常构建中使用它,因为它会增加太多噪音,但如果你想保留它,@Kurt Stutsman 在评论中提到了一个很好的解决方案:

clang++(g++ 在任何情况下都不会发出警告)不会发出警告,如果您使用 reinterpret_cast 而不是 c 样式转换(您无论如何都不应该使用) ,尽管两者(在本例中)具有完全相同的功能。可能是因为 reinterpret_cast 明确告诉编译器:“相信我,我知道我在做什么”


旁注:在 C++ 代码中,您不需要 struct 关键字。

关于c++ - 从 sockaddr * 转换为 sockaddr_in * 增加了所需的对齐方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35551879/

有关c++ - 从 sockaddr * 转换为 sockaddr_in * 增加了所需的对齐方式的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  3. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  4. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  5. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  6. ruby-on-rails - Rails 3 I18 : translation missing: da. datetime.distance_in_words.about_x_hours - 2

    我看到这个错误:translationmissing:da.datetime.distance_in_words.about_x_hours我的语言环境文件:http://pastie.org/2944890我的看法:我已将其添加到我的application.rb中:config.i18n.load_path+=Dir[Rails.root.join('my','locales','*.{rb,yml}').to_s]config.i18n.default_locale=:da如果我删除I18配置,帮助程序会处理英语。更新:我在config/enviorments/devolpment

  7. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  8. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  9. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  10. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

随机推荐