【问题标题】:difference between time() and gettimeofday() and why does one cause seg faulttime() 和 gettimeofday() 之间的区别以及为什么会导致段错误
【发布时间】:2013-10-31 23:03:19
【问题描述】:

我正在尝试测量系统调用的时间量,并尝试在此程序中使用time(0)gettimeofday(),但每当我使用gettimeofday() 时,它都会出现段错误。我想我可以使用time(0),但我想知道为什么会这样。我知道你们可以看看它,看看问题所在。请不要对我大喊大叫!

我想获取时间,但不想将其保存在任何地方。

我已经尝试了所有我能想到的代码组合,但我在这里粘贴了最简单的版本。我是 C 和 Linux 的新手。我查看了 .stackdump 文件,但它对我来说毫无意义。

GetRDTSC 在 util.h 中,它确实是 rdtsc(),正如人们所预料的那样。现在它设置为 10 次迭代,但稍后循环将运行 1000 次,没有printf

#include <stdio.h>
#include <time.h>
#include "util.h"

int main() {

    int i;
    uint64_t cycles[10];

    for (i = 0; i < 10; ++i) {

         // get initial cycles
         uint64_t init = GetRDTSC();

         gettimeofday(); // <== time(0) will work here without a seg fault.

         // get cycles after
         uint64_t after = GetRDTSC();   

         // save cycles for each operation in an array
         cycles[i] = after - init;

         printf("%i\n", (int)(cycles[i]));
    }  
}

【问题讨论】:

  • 只是想了解如何编译这段代码?

标签: c linux time segmentation-fault


【解决方案1】:

短版

gettimeofday() 需要一个指向struct timeval 的指针来填充时间数据。

所以,例如,你会做这样的事情:

#include <sys/time.h>
#include <stdio.h>
int main() {  
    struct timeval tv;
    gettimeofday(&tv, NULL); // timezone should be NULL
    printf("%d seconds\n", tv.tv_secs);
    return 0;
}

长版

真正的问题是 gcc 会自动在您的系统上包含vdso,其中包含系统调用gettimeofday 的符号。考虑这个程序(整个文件):

int main() {
  gettimeofday();
  return 0;
}

默认情况下,gcc 会编译这个没有警告。如果您检查它所链接的符号,您会看到:

ternus@event-horizon ~> gcc -o foo foo.c
ternus@event-horizon ~> ldd foo
        linux-vdso.so.1 =>  (0x00007ffff33fe000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f56a5255000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f56a562b000)

您只是碰巧使用了一个具有已定义符号的函数,但没有原型,就无法知道它应该有多少命令行参数。

如果你用-Wall编译它,你会看到:

ternus@event-horizon ~> gcc -Wall -o foo foo.c
foo.c: In function ‘main’:
foo.c:2:3: warning: implicit declaration of function ‘gettimeofday’ [-Wimplicit-function-declaration]

当然,当您尝试运行它时,它会出现段错误。有趣的是,它会在内核空间出现段错误(这是在 MacOS 上):

cternus@astarael ~/foo> gcc -o foo -g foo.c
cternus@astarael ~/foo> gdb foo
GNU gdb 6.3.50-20050815 (Apple version gdb-1822) (Sun Aug  5 03:00:42 UTC 2012)
[etc]

(gdb) run
Starting program: /Users/cternus/foo/foo
Reading symbols for shared libraries +.............................. done

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000001
0x00007fff87eeab73 in __commpage_gettimeofday ()

现在考虑这个程序(同样,没有头文件):

typedef struct {
  long tv_sec;
  long tv_usec;
} timeval;

int main() {
  timeval tv;
  gettimeofday(&tv, 0);
  return 0;
}

这将编译并运行得很好——没有段错误。您已经为它提供了它所期望的内存位置,尽管仍然没有提供 gettimeofday 原型。

更多信息:

Can anyone understand how gettimeofday works?

Is there a faster equivalent of gettimeofday?

The POSIX gettimeofday specification

【讨论】:

  • 它实际上需要两个参数:timeval 和 timezone
  • 对。 “时区结构的使用已过时;tz 参数通常应指定为 NULL。” linux.die.net/man/2/gettimeofday
  • 这不会导致错误的参数数量错误,而不是段错误吗?因为我不想节省时间,所以我尝试使用 gettimeofday(0,0),它给出的结果与 gettimeofday() 相同。添加 &tv 会为操作添加周期吗?
  • @punstress:如果您使用正确的编译器选项 (-Werror=implicit-function-declaration),它会。向 gcc 开发人员抱怨这个选项仍然不是默认选项(这应该总是一个错误,而不是警告;它是无效的 C 并且非常危险)。
猜你喜欢
  • 2020-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-04
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
相关资源
最近更新 更多