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;a1a2 在行后设置为 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有啥区别? [复制]

在 linux 上,使用 C/C++ 编程时,我应该使用啥函数来输入密码? [复制]

fflush(stdin) 在 C 编程中有啥作用? [复制]