C 编程#define? [复制]
Posted
技术标签:
【中文标题】C 编程#define? [复制]【英文标题】:C Programming #define? [duplicate] 【发布时间】:2011-05-04 00:39:27 【问题描述】:可能重复:Could anyone explain these undefined behaviors (i = i++ + ++i , i = i++, etc…)
#include<stdio.h>
#include<conio.h>
#define SQ(x) x*x
void main()
int a1 , a2;
int b1 , b2;
a1 = 2;
a2 = 2;
b1 = 0;
b2 = 0;
b1 = SQ(a1++);
b2 = SQ(++a2);
printf("Frist = %d",b1);
printf("Second = %d",b2);
我知道代码的输出是什么。
在其他程序中作为#define 工作 这样它就不能在上面的代码中工作 为什么。?
【问题讨论】:
当你编译并执行这个时会发生什么?错误?奇怪的结果?什么? 你期望的输出是什么,你得到了什么?我很确定在 x++ * x++ 和 ++y*++y* 中,第一个增量是否在第二个被评估时发生是未定义的,所以你得到的值会因环境而异 在你原来的问题中,有一个错字(#deifne
而不是#define
)我现在更正了,确保你使用的代码是正确的。
【参考方案1】:
我真的不知道你的问题是什么,但也许你的预期输出有问题......
请注意,#define
是在您的代码编译之前运行的“简单”文本替换。
此文本替换不尊重范围或语法正确性。它只是替换与您所说的内容匹配的任何内容。
在您的情况下,它不会真正对“a++”的结果进行平方,而是会
生成此代码:b1 = a++ * a++;
如果你看这里:Question about C programming 你可以看到一些解释为什么“a++ * a++”是官方未定义的行为。
【讨论】:
【参考方案2】:恭喜!您刚刚发现为什么将宏用于此类事情是一个坏主意。作为一般规则,只有当它不能使用函数来完成时,才将其设为宏。在这种情况下,SQ
可以很容易地实现为一个函数:
int sq (int x)
return x * x;
【讨论】:
+1 表示比 C++ 语言奥秘更重要的一点【参考方案3】:在同一个变量上具有多个 ++ 运算符的表达式的结果在 C 中正式成为未定义的行为。
【讨论】:
这在技术上是“未定义的行为”吗?我认为这是“未指定的行为”,这仍然很糟糕,但将实现限制为某些选择(在这种情况下不包括崩溃)。 是的,它肯定是未定义的;)。 顺便说一句,这个答案并不完全正确。一个表达式可以多次修改同一个变量 - 只有在这些修改之间没有序列点(即 &&、||、?:、逗号运算符或函数调用)时,行为才被定义 我不是语言律师 :) 我也不会在电视上播放。【参考方案4】:线条
b1 = SQ(a1++);
b2 = SQ(++a2);
展开到
b1 = a1++ * a1++;
b2 = ++a2 * ++a2;
调用未定义的行为(一个对象可能在序列点之间最多修改一次其值),这意味着任何结果都被认为是“正确的”。
这就是这类宏的问题;您确实希望参数被评估一次,但是由于扩展,它被评估了两次。
用这样的表达式调用它也有问题
x = SQ(a + b);
这将扩展为
x = a + b * a + b;
这可能不是你想要的。为了保持操作符优先级,扩展应该被包裹在()
中,比如
#define SQ(x) (x) * (x)
【讨论】:
最后一点,您还需要将整个表达式括在括号中,即#define SQ(x) ((x) * (x))
否则像 x = -SQ(4)
这样的表达式可能会产生意想不到的结果。
@JeremyP:哎呀,是的,你是对的。你能说我不经常使用这样的宏吗?【参考方案5】:
查看代码,因为它将被预处理器扩展:
b1 = a1++ * a1++;
b2 = ++a2 * ++a2;
这是未定义的行为,因为您不止一次地修改了一个变量,它们之间没有序列点。
【讨论】:
【参考方案6】:#define
是预处理器的一条指令,用它的扩展字面替换每个出现的宏。因此,您代码中的相关行将传递给编译器:
b1 = a1++ * a1++;
b2 = ++a2 * ++a2;
正如 Seva 所说,这些表达式在官方上是未定义的;但即使我们采用可以说是最明智的阅读方式,您仍然会得到 b1 = 2 * 3;
和 b2 = 3 * 4;
(a1
和 a2
在行后设置为 4。
【讨论】:
【参考方案7】:将宏中的操作数用括号括起来:
#define SQ(X) (X)*(X)
另外,尽量不要在同一个赋值中使用 x++ 和 x。可能导致未定义的行为。
干杯!
【讨论】:
【参考方案8】:SQ 的两种用法都会调用未定义的行为,因为它们在每个序列点多次分配给 a1 和 a2。您不应将具有副作用的表达式(例如赋值或增量)传递给宏。
【讨论】:
【参考方案9】:因为define 只是替换了表达式。所以你得到结果:
b1 = (a1++)*(a1++);
b2 = (++a2)*(++a2;
因此,您获得两次双倍增量。它会导致未定义的行为。
【讨论】:
您在展开式中添加了一些括号。在这种情况下,这没有任何区别,但有时会产生很大的不同。 @Darron 同意你的看法。为了便于阅读。以上是关于C 编程#define? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 中的 define([ , function ]) 是啥? [复制]
《Windows核心编程》第3章——handle复制相关实验
在Linux系统系下vi操作中C语言编程,如何进行复制粘贴?求救!
RequireJS中的define和require有啥区别? [复制]