【问题标题】:Getting RAM size in C, linux, non-precise result在 C、Linux、非精确结果中获取 RAM 大小
【发布时间】:2014-03-26 18:42:40
【问题描述】:

我在学校运行 Ubuntu 13.10 的计算机上有 16 GB RAM。我编写了一个简单的 C 程序来获取总 RAM,但它显示了不精确的结果,而不是 16,它打印出 15。如何使其精确,即使对于较小的 RAM 尺寸?在家里,我有一台 768 MB RAM 的电脑,我的程序也显示错误的结果:(

#include <sys/sysctl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>

void getMemoryInfo()
{
    FILE *meminfo = fopen("/proc/meminfo", "r");
    int totalMemory = 0;
    if(meminfo == NULL)
    {
        exit(-1);
    }
    char buff[256];
    while(fgets(buff, sizeof(buff), meminfo))
    {
        int ramKB;
        if(sscanf(buff, "MemTotal: %d kB", &ramKB) == 1)
        {
            totalMemory = ramKB/1024.0;
            totalMemory = totalMemory/1024.0;
        }
    }
    if(fclose(meminfo) != 0)
    {
        exit(-1);
    }
    printf("%d\n", totalMemory);
}

int main()
{
    getMemoryInfo();

    return 0;
}

【问题讨论】:

标签: c ram


【解决方案1】:

我曾经使用过这段代码。 . .适用于大多数操作系统

#if defined(_WIN32)
#include <Windows.h>

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#if defined(BSD)
#include <sys/sysctl.h>
#endif

#else
#error "Unable to define getMemorySize( ) for an unknown OS."
#endif

/**
 * Returns the size of physical memory (RAM) in bytes.
 */
size_t getMemorySize( )
{
#if defined(_WIN32) && (defined(__CYGWIN__) || defined(__CYGWIN32__))
    /* Cygwin under Windows. ------------------------------------ */
    /* New 64-bit MEMORYSTATUSEX isn't available.  Use old 32.bit */
    MEMORYSTATUS status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatus( &status );
    return (size_t)status.dwTotalPhys;

#elif defined(_WIN32)
    /* Windows. ------------------------------------------------- */
    /* Use new 64-bit MEMORYSTATUSEX, not old 32-bit MEMORYSTATUS */
    MEMORYSTATUSEX status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatusEx( &status );
    return (size_t)status.ullTotalPhys;

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
    /* UNIX variants. ------------------------------------------- */
    /* Prefer sysctl() over sysconf() except sysctl() HW_REALMEM and HW_PHYSMEM */

#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
    int mib[2];
    mib[0] = CTL_HW;
#if defined(HW_MEMSIZE)
    mib[1] = HW_MEMSIZE;            /* OSX. --------------------- */
#elif defined(HW_PHYSMEM64)
    mib[1] = HW_PHYSMEM64;          /* NetBSD, OpenBSD. --------- */
#endif
    int64_t size = 0;               /* 64-bit */
    size_t len = sizeof( size );
    if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 )
        return (size_t)size;
    return 0L;          /* Failed? */

#elif defined(_SC_AIX_REALMEM)
    /* AIX. ----------------------------------------------------- */
    return (size_t)sysconf( _SC_AIX_REALMEM ) * (size_t)1024L;

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
    /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
    return (size_t)sysconf( _SC_PHYS_PAGES ) *
        (size_t)sysconf( _SC_PAGESIZE );

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGE_SIZE)
    /* Legacy. -------------------------------------------------- */
    return (size_t)sysconf( _SC_PHYS_PAGES ) *
        (size_t)sysconf( _SC_PAGE_SIZE );

#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
    /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
    int mib[2];
    mib[0] = CTL_HW;
#if defined(HW_REALMEM)
    mib[1] = HW_REALMEM;        /* FreeBSD. ----------------- */
#elif defined(HW_PYSMEM)
    mib[1] = HW_PHYSMEM;        /* Others. ------------------ */
#endif
    unsigned int size = 0;      /* 32-bit */
    size_t len = sizeof( size );
    if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 )
        return (size_t)size;
    return 0L;          /* Failed? */
#endif /* sysctl and sysconf variants */

#else
    return 0L;          /* Unknown OS. */
#endif
}

【讨论】:

    【解决方案2】:

    您看到的是浮点不准确造成的。在浮点数和整数之间以及打印浮点数时必须小心。

    由于浮点数不能准确地表示所有数字,它经常尝试尽可能接近。可能发生的情况是,totalMemory 不是 16,而是类似于 15.999999999987,然后当它转换为 int 时,它会被截断为 15。

    有两种方法可以解决这个问题:如果您知道totalMemory 可以被1024*1024 整除,那么只需使用整数(这在非整数千兆字节的情况下不起作用)。由于无论如何您都在使用整数,因此您不妨使用这种方法。 (768MB 不能表示为 GB 的整数)。

    另一个选项是添加一个 epsilon 来防止这种情况。换句话说,您可以使用totalMemory + 1e-7 之类的东西,而不是使用totalMemory。 epsilon 太微不足道,无法产生有意义的影响,但它可以将 15.999... 之类的东西推到 16


    顺便说一句,浮点问题只是您问题的一部分。如果您要使用整数,您可能希望使用 MB 而不是 GB。一个整数怎么能代表 4.5GB(尽管现在这种情况非常少见)?

    【讨论】:

    • 这里的FP绝对不是精度问题,双打有52位尾数,我们处理的是整数,所以我们可以达到2^53-1而不会损失任何精度。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    • 2011-05-13
    • 2016-12-26
    相关资源
    最近更新 更多