关于宏返回值的问题

如果想对于基本函数进行一次封装比如说我调用基本函数fseek的时候错误的时候想要输出一句日志,每次都来一次下面的判断还是比较崩溃的.

if (fseek(...) != 0)

{
	printf("fseek error %s\n", strerror(errno));
}

所以对于这种基本系统调用进行一个封装是比较好的一个思路, 第一个想到的就是下面这种思路,但是可以看到多少还是有点别扭

int fseek(FILE *stream, long offset, int whence);
#define FSEEK(stream, offset, whence, ret) \
	do { \
		ret = fseek(stream, offset, whence, ret); \
		if (ret != 0) \
			printf("xxxx"); \
	} while(0)
		
int main()
{
	...
	
	int ret = 0;
	FSEEK(stream, offset, whence, ret);
	if (ret != 0)
	{
		return -1;
	}
	
	...
}

最后看到另外一个宏定义

#define FOPEN(path, mode) ({ \
		FILE* ret = 0; \
		ret = fopen(path, mode); \
		if (ret == NULL)\
		{ \
			printf("err %s\n", strerror(errno)); \
		} \
		ret; \
		})

int main(int argc, char** argv)
{
	if (FOPEN(argv[1], "rb+") == NULL)
	{
		printf("open error");
	}
}

其实上面的函数可以通过宏展开看下具体展开后 gcc -E test.cpp

int main(int argc, char** argv)
{


 if (({ FILE* ret = 0; ret = fopen(argv[1], "rb+"); if (ret == 
    ((void *)0)
    ) { printf("err %s\n", strerror(
    (*__errno_location ())
    )); } ret; }) == 
                             ((void *)0)
                                 )
 {
  printf("open error");
 }
}


整理后如下

int main(int argc, char** argv)
{
 if (	({ 
			FILE* ret = 0; 
			ret = fopen(argv[1], "rb+"); 
			if (ret == ((void *)0)) 
				{ printf("err %s\n", strerror((*__errno_location ()))); } 
		ret; }) == ((void *)0)
    )
 {
  printf("open error");
 }
}


### 定义如何返回值 在 C/C++ 中,定义本质上是预处理器指令,在编译前进行文本替换。通过巧妙使用表达式结构,可以实现“返回值”的效果。 #### 使用逗号表达式返回最后一个操作的值 可以通过逗号表达式将多个操作组合在一起,并返回最后一个表达式的值。例如: ```c #include <stdio.h> #define A(w, x, y, z) (w = x, x = y, y = z, z = w) int main() { int a = 1, b = 2, c = 3, d = 4; printf("%d", A(a, b, c, d)); // 输出为 2 return 0; } ``` 在该示例中,`A(a, b, c, d)` 被展开为 `(a = b, b = c, c = d, d = a)`,其中逗号 `,` 确保了各赋值操作顺序执行,最终返回的是 `d = a` 的结果,即 `2` [^3]。 #### 使用三目运算符返回条件判断值 也可以结合三目运算符(`? :`)实现根据条件返回不同的值。例如: ```c #include <stdio.h> #define SECOND_OF_YEAR(__YEAR__) ((__YEAR__ % 100 != 0 && __YEAR__ % 4 == 0) ? 366 * 24 * 3600 : 365 * 24 * 3600) int main() { printf("Seconds in 2024: %d\n", SECOND_OF_YEAR(2024)); return 0; } ``` 此根据年份是否为闰年计算一年中的总秒数,若为闰年则返回 `366 * 24 * 3600`,否则返回 `365 * 24 * 3600` [^4]。 #### 使用代码块语句返回字符串或复杂逻辑值 通过 GNU 扩展的语句表达式(`({ ... })`),可以包含多行代码并返回一个值。例如: ```c #include <stdio.h> #define REGREAD(_DAYOFWEEK_) ({ \ char* str; \ switch (_DAYOFWEEK_) { \ case 1: case 2: case 3: case 4: case 5: \ str = "小伙子,好好上班!"; break; \ case 6: case 7: \ str = "小伙子,来加个班呀!"; break; \ default: \ str = "小伙子,今年过年别回家了,加个班吧!"; break; \ } \ str; }) int main() { for(int i = 0; i <= 7; i++) { printf("%s\n", REGREAD(i)); } return 0; } ``` 该根据传入的星期数值,使用 `switch` 判断并返回对应的字符串提示信息 [^5]。 --- ### 总结 C/C++ 定义虽然不是函数,但通过表达式、逗号分隔、三目运算符和 GNU 语句表达式等机制,可以模拟具有“返回值”的行为。这种技术广泛用于常量定义、条件逻辑处理和复杂表达式计算中。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值