【问题标题】:Have macro 'return' a value让宏“返回”一个值
【发布时间】:2011-02-10 08:57:16
【问题描述】:

我正在使用宏,我认为它可以正常工作 -

#define CStrNullLastNL(str) {char* nl=strrchr(str,'\n');如果(nl){*nl=0;}}

所以它可以将字符串中的最后一个换行符归零,实际上它用于在 fgets 保留它时切断换行符。

所以,我想知道我是否可以从宏中“返回”一个值,以便可以像这样调用它

func(CStrNullLastNL(cstr));

或者我必须写一个函数

【问题讨论】:

  • 你不必写任何一个 - 只需使用strtok(str, "\n")。虽然它不是 strtok() 真正设计的用途,但它完美地完成了工作(事实上,它是 strtok() 的少数好用途之一)。在 C++ 中,您应该只使用 std::getline() 而不是 fgets()。
  • 你希望它返回什么?
  • @Jerry Coffin:这不会替换第一个换行符而不是最后一个换行符吗?
  • @Fred:fgets 只读取一行,因此第一行也是最后一行(并且始终是字符串中的最后一个字符,如果存在的话)。如果你在一些完全不同的情况下使用,你可能有多个,那么是的,它会从第一个停止。
  • 如果您知道\n 是字符串的最后一个字符或不存在,那么您不需要比strlen() 更高级的东西。

标签: c++ macros return-value


【解决方案1】:

宏不返回值。宏告诉预处理器将#define 之后的内容替换为#define 之后的内容。结果必须是有效的 C++。

您要求的是如何使以下内容有效:

func( {char* nl=strrchr(str,'\n'); if(nl){*nl=0;}} );

除了让它成为真正的函数调用之外,我想不出一个好方法来把它变成有效的东西。在这种情况下,我不确定为什么宏会比内联函数更好。这似乎是你真正想要的。

【讨论】:

  • 将其变为有效的一个好方法是使用({ }) GCC 扩展。但这显然只适用于 GCC。当然,我同意内联函数会更好。
【解决方案2】:

返回值是内联函数的用途。而且很多时候,所说的内联函数比宏更适合任务,宏非常危险并且没有安全类型。

【讨论】:

    【解决方案3】:
    #define CStrNullLastNL(str) ({ \
        char* nl=strrchr(str,'\n');\
        if(nl){*nl=0;} \
        nl; \
    })
    

    应该可以。

    编辑:...在 GCC 中。

    【讨论】:

    • @jeffamaphone:当然没有。 ({ }) 构造是 GCC 扩展。
    • 一个该死的有用的扩展,我可能会补充。
    • @jeffamaphone:当然它不是便携式的。毕竟,这就是“扩展”的定义。 :)
    • ({ }) 构造究竟做了什么?评估到最后一条语句?
    • @bobobobo 是的,它评估最后一条语句。请记住,括号 () 和花括号{} 都是必需的。
    【解决方案4】:

    对于要“返回值”的宏,宏本身必须是一个表达式。您的宏是一个语句块,不能计算为表达式。

    你真的应该写一个inline 函数。它将同样快速且更易于维护。

    【讨论】:

    • 现在的编译器,内联修饰符不是隐含的吗?
    • 视情况而定。 1) 即使它是隐式的,也可以用它告诉其他阅读您的代码的人该函数应该内联。 2) inline 可能会抑制非内联版本的生成。默认情况下,通常会将非内联版本发送到对象中“以防万一”,另一个对象中的代码需要获取该函数的地址(一元&)。标记它inline 也可以告诉编译器获取函数的地址应该是一个错误。如果您真的想查看实际结果,请使用 gcc -S 之类的内容。
    • 如果您将函数主体写入头文件(可能包含在多个实现文件中),这也是必要的 - 否则会出现链接器错误
    • ... 在我最后一次发言一周后,没有任何解释,投了反对票。其他人经常发生这种情况吗? O_o
    • 如果你需要sizeof,你应该写一个内联模板函数。
    【解决方案5】:

    我给 Mike +1 是因为他 100% 正确,但如果你想将其作为宏来实现,

    char *CStrNullLastNL_nl; // "private" global variable
    #define nl ::CStrNullLastNL_nl // "locally" redeclare it
    #define CStrNullLastNL( str ) ( \
        ( nl = strrchr( str, '\n') ), /* find newline if any */ \
        nl && ( *nl = 0 ), /* if found, null out */ \
        (char*) nl /* cast to rvalue and "return" */ \
    OR  nl? str : NULL /* return input or NULL or whatever you like */
    )
    #undef nl // done with local usage
    

    【讨论】:

    • @Mike: 1. 我在两行代码之间加上“或”,因为 Oraz 提出了不同的行为。注意缺少逗号。 2. 不可重入。宏一开始是个坏主意。 3. 我想。将两个线程放在不同的源文件中并使其也可重入!都是愚蠢的练习。
    【解决方案6】:

    如果你真的想这样做,请获取支持 C++0x 样式 lambda 的编译器:

    #define CStrNullLastNL(str) [](char *blah) {char* nl=strrchr(blah,'\n'); if(nl){*nl=0;} return blah;}(str)
    

    虽然CStrNullLastNL 基本上是一个函数,但你可能应该将它重写为一个函数。

    【讨论】:

    • 非常聪明,喜欢它。在一个特定的用例中,我想要一个库中的一个辅助函数,该函数对没有定义的对象进行操作。但是这些定义将在实际使用辅助函数的任何代码中可用。 (例如,带有和不带gui 模块的Qt。)将其隐藏在宏后面,但仍保持具有正确对象类型的良好定义的函数似乎是一个很好的折衷方案。 #define qtKeyEventNativeModifiers(qkeyevent) [](QKeyEvent *event) { return (event->nativeScanCode() & 0xff); }(qkeyevent)(QKeyEvent 仅在某些版本中可用)。
    【解决方案7】:

    你可以使用逗号运算符吗?简化示例:

    #define SomeMacro(A) ( DoWork(A), Permute(A) )
    

    这里 B=SomeMacro(A) “返回” Permute(A) 的结果并将其分配给“B”。

    【讨论】:

    • 当然可以,但不能将控制流语句放在表达式中。这就是它变得棘手的地方。
    • ?: 运算符在表达式中作为控制流工作得很好。我一直在使用它。
    【解决方案8】:

    如果你没有严格要求只使用宏,你可以这样做(现实生活中的例子):

    #define Q_XCB_SEND_EVENT_ALIGNED(T) \
        q_xcb_send_event_aligned<T>()
    
    template<typename T> inline
    T q_xcb_send_event_aligned()
    {
        union {
            T event;
            char padding[32];
        } event;
    
        memset(&event, 0, sizeof(event));
        return event.event;
    }
    

    然后像这样在你的代码中使用它:

    auto event = Q_XCB_SEND_EVENT_ALIGNED(xcb_unmap_notify_event_t);
    

    【讨论】:

      【解决方案9】:

      从宏返回值:

      bool my_function(int a) {
          if (a > 100)return true;
          return false;
      }
      bool val = my_function(200);
      
      #define my_macro(ret_val,a){\
          if(a > 100 ) ret_val = true;\
          ret_val = false;\
      }
      bool val; my_macro(val, 200);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-15
        • 2021-08-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多