【问题标题】:Casting a long int to void *将 long int 转换为 void *
【发布时间】:2013-07-06 13:53:58
【问题描述】:

这是将long 转换为void * 的正确方法吗?在Qt 程序中使用-O2 时出现段错误。使用-O1时不会出现段错误。

当使用reinterpret_cast<void *>(tp.tv_nsec) 时,使用-O2 时也会出现段错误。

为什么会出现段错误?

timespec tp; // struct that holds nanoseconds since Epoch
clock_gettime(CLOCK_REALTIME, &tp); // tv_nsec is a long int

void *test = mmap((void *)(tp.tv_nsec), 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

printf("%p\n", test);
printf("%li\n", (long)test);

编辑: AFAIK,目标似乎表达错误。目标是获取一个随机数以分配一个随机内存地址。这样,每次我在整个测试程序中多次使用 mmap() 时,我都会得到一个随机内存地址。如果不是, mmap() 似乎是按顺序分配内存。

【问题讨论】:

  • 当前时间和地址有什么关系?
  • 你到底想干什么?无论您是否有-O1 或-O2,此段错误是否取决于您运行它的确切时间。但是我看不到目的-您是否想查看mmap 是否已安全实现,以便如果您获取random 地址并将其输入,它将做正确的事情,或者您为什么要这样做?

标签: c++ linux 64-bit posix


【解决方案1】:

转换无效,因为tp.tv_nsec 不是地址:

mmap((void *)(tp.tv_nsec), 4096,
                 ^ 
                 |  is not an address

试试这个:

mmap((void *) &(tp.tv_nsec), 4096,
              ^
              |  amperson operator for address

&是地址(操作数)运算符给出变量的地址

【讨论】:

  • 虽然这确实给出了一个地址,但我非常怀疑它是否是一个有用的地址给mmap,因为它应该是一个未使用的内存区域。除了mmap((void *)rand(), ...) 的替代品之外,我看不出这段代码对任何东西都有用 - 这也是没用的。
  • @Mats Petersson 真的没有。这只是 MAP_FIXED 的情况。请参阅我对 Jens Gustedt 的评论。
【解决方案2】:

我不知道为什么您将变量转换为地址变量,但您的优化设置之一与此相反:

-O2 打开所有由-O 指定的优化标志。它还开启了以下优化标志:

      -fthread-jumps 
      -falign-functions  -falign-jumps 
      -falign-loops  -falign-labels 
      -fcaller-saves 
      -fcrossjumping 
      -fcse-follow-jumps  -fcse-skip-blocks 
      -fdelete-null-pointer-checks 
      -fdevirtualize 
      -fexpensive-optimizations 
      -fgcse  -fgcse-lm  
      -fhoist-adjacent-loads 
      -finline-small-functions  ----------> Result: this is causing the segfault(elaine has found so +1 to him please).
      -findirect-inlining 
      -fipa-sra 
      -foptimize-sibling-calls 
      -fpartial-inlining 
      -fpeephole2 
      -fregmove 
      -freorder-blocks  -freorder-functions 
      -frerun-cse-after-loop  
      -fsched-interblock  -fsched-spec 
      -fschedule-insns  -fschedule-insns2 
      -fstrict-aliasing                 --------> I thought this was issue(void * from long) but is not
      -fstrict-overflow 
      -ftree-switch-conversion -ftree-tail-merge 
      -ftree-pre 
      -ftree-vrp

我怀疑:

-fstrict-aliasing 允许编译器采用适用于正在编译的语言的最严格的别名规则。对于 C(和 C++),这会根据表达式的类型激活优化。特别是,假设一种类型的对象永远不会与不同类型的对象驻留在相同的地址,除非类型几乎相同。例如,unsigned int 可以给 int 取别名,但不能给 void* 或 double 取别名。字符类型可以别名任何其他类型。

我错了,真丢脸。

 >:c

根据elaine所说,-finline-small-functions是问题的根源。

http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

【讨论】:

  • 实际上,段错误与-finline-small-functions有关。感谢您为我指明正确的方向。
【解决方案3】:

使用 reinterpret_cast<void *>(tp.tv_nsec) 构造,您将 long 并将其解释为指针。这会导致错误的内存访问。你应该把它的地址转换成void*:reinterpret_cast<void *>(&tp.tv_nsec)

【讨论】:

    【解决方案4】:

    答案是 C 的,但我想 C++ 的答案是相似的。不能保证从整数类型到指针的转换在所有情况下都有效,因为它们可能具有不同的宽度并且指针可能被分段。如果有一个整数类型适用于你的平台,它应该是 typedefed 到 [u]intptr_t,所以如果你必须这样做,请使用该类型。

    那么您正在使用mmap 处理一些根本无法预见的事情。如果您将地址传递给它,则您有责任验证这是您地址空间中的有效地址以用于该地址。例如,它必须是页面大小的倍数,但可能适用其他限制。检查mmap调用的返回值是否成功。

    首先,最好阅读系统随附的文档。 man mmap 是你的朋友。

    【讨论】:

    • mmap() "addr 的非零值被认为是应该放置映射的进程地址的建议。"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    • 2020-11-21
    • 1970-01-01
    相关资源
    最近更新 更多