从宏等函数访问返回值

时间:2013-10-15 23:33:11

标签: c macros c-preprocessor header-files

最近,我正在阅读JOS Kernel的代码(在麻省理工学院开发,主要是为了帮助像我这样的初学者学习目的),并提出一个小小的疑问,我认为这可能是微不足道的但是无法弄清楚这样发布在这里求助..

这是来自" .c" 文件的一小段代码: -

if(n>0)
           {
            nextfree = ROUNDUP((char *) nextfree, PGSIZE);
            result=nextfree;
            nextfree+=n;
            PADDR(nextfree);
           }

对应的" .h" 文件: -

/* This macro takes a kernel virtual address -- an address that points above
* KERNBASE, where the machine's maximum 256MB of physical memory is mapped --
* and returns the corresponding physical address.  It panics if you pass it a
* non-kernel virtual address.
*/

    #define PADDR(kva)                      \
    ({                              \
    physaddr_t __m_kva = (physaddr_t) (kva);        \
    if (__m_kva < KERNBASE)                 \
    panic("PADDR called with invalid kva %08lx", __m_kva);\
    __m_kva - KERNBASE;                 \
    })

现在我对上述结构有两个问题 -

  1. 我们不应该将PADDR(nextfree)的值分配给某个变量,例如var=PADDR(nextfree),而不是像上面那样直接调用它。它将如何运作?

  2. 为什么有人喜欢在头文件中编写如此小而复杂的定义,而不是为易于掌握的指定任务创建函数。

2 个答案:

答案 0 :(得分:4)

当您调用宏时,编译器会在此时将宏定义替换为您的代码。除非宏恰好扩展为具有返回值的东西,否则没有“返回值”。

这个结构:

 ( { /* ... */ } )

是一个特定于gcc的扩展,称为“语句表达式”,记录为here。它由括在括号中的复合语句组成,它产生最后一个表达式的值。 (如果; }之前的最后一件事不是表达式,那么整件事就不会产生值。)

PADDR()宏获取内核虚拟地址kva并生成相应的物理地址。如果虚拟地址无效,则会发生混乱。 (它可能是作为一个函数编写的,但是作者选择使用宏,可能是为了效率。inline函数可能达到了相同的目标。)

在您展示的使用PADDR

的代码中
if (n > 0) {
    /* snip */
    PADDR(nextfree);
}

调用PADDR宏,但丢弃它产生的值。假设这不是错误,如果nextfree不是有效的虚拟地址,则可能会强制执行此操作。代码不使用生成的物理地址,因为它不需要它;检查就是它所需要的。

它仍然计算__m_kva - KERNBASE;,这可能有点浪费,但我怀疑成本是否很高 - 并且优化编译器可能会认识到结果未被使用,并且丢弃计算。 / p>

答案 1 :(得分:1)

嗯......取消这个:

  1. 请注意那些parens。这意味着它内部的任何东西都会减少到一个值......
  2. 注意大括号:我们在这里定义一个新的块范围。
  3. 现在我们处于新的范围,我们可以安全地定义我们喜欢的任何变量,因为它们不会逃避这个块。
  4. 最后一个语句包含一个表达式。
  5. 因此,范围的值是最后一个语句中该表达式的值。
  6. 因此宏的返回值为__m_kva - KERNBASE
  7. 所以回答问题1:它确实返回一个值,但是在你的示例代码片段中,这个返回的值根本就不用了。但是,据推测,调用宏的其他代码确实使用了该值。回答问题2:这取决于。你可以用宏来做一些你根本不能用函数做的事情,比如它们undefining。在这种情况下,程序员似乎需要复制常见的错误检查,并使用转换宏在示例代码段中执行此操作。 (它提前检查下一个空闲不会无意中尝试free用户空间内存或类似内容。)