困惑于C宏展开和整数算术

3

可能是重复内容:
一道谜题(使用 C 语言)

以下代码片段中,我有几个问题:

#include<stdio.h>

#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};

int main()
{
int d;

for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);

return 0;
}

这里代码的输出并不像预期那样打印数组元素。但是当我在 ELEMENTS 的宏定义中添加一个 (int) 类型转换时,问题得到了解决。

 #define TOTAL_ELEMENTS (int) (sizeof(array) / sizeof(array[0]))

它按预期显示了所有数组元素。

  • 这种类型转换是如何工作的?

基于此,我有几个问题:

  • 这是否意味着如果我有以下宏定义:

    #define AA (-64)

默认情况下,在C语言中,所有定义为宏的常量都等同于 signed int

如果是这样,那么

  • 但是,如果我必须强制某个在宏定义中定义的常量行为类似于无符号整数,是否存在任何常数后缀可以使用(我尝试了UL,UD,但都不起作用)?

  • 如何在宏定义中定义一个常量以行为无符号整数?

4个回答

12

看看这一行:

for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)

在第一次迭代中,你正在检查是否

-1 <= (TOTAL_ELEMENTS-2)

运算符size_of返回无符号值,因为在32位机器上,-1有符号数等于0xFFFFFFFF无符号数,所以检查失败。

循环中进行简单的更改即可解决该问题:

for(d=0;d <= (TOTAL_ELEMENTS-1);d++)
printf("%d\n",array[d]);

回答你的其他问题:C宏是文本替换,没有类型这个概念。C编译器将你的循环视为:

for(d=-1;d <= ((sizeof(array) / sizeof(array[0]))-2);d++)

如果你想在宏中定义一个无符号常量,使用通常的后缀(u表示unsignedul表示unsigned long)。


@Miroslav:在宏中定义无符号常量时,我应该使用什么后缀? - goldenmean
3
这是循环遍历数组的C语言惯用法: 定义整型变量i,使用for循环从0开始遍历数组,直到小于数组长度为止。 具体代码如下: int i; for (int i=0; i < arrLen; i++) { printf("%d\n", arr[i]); } - plinth

8

sizeof 返回无符号格式的字节数。 这就是为什么你需要进行强制类型转换。

更多信息请参见此处


@Skurmedel:没问题。但如果我定义一个宏如下: #define bb (-64*(sizeof(int)/sizeof(int)))然后使用bb,它会表现为有符号整数,我认为它应该表现为无符号整数,因为在bb的宏定义中,有一个有符号整数乘以一个无符号整数,所以结果应该是无符号整数(按C语言提升规则)。我是不正确还是漏了什么? - goldenmean
1
根据C99标准(6.3.1.8):否则,如果带有有符号整数类型的操作数的类型可以表示带有无符号整数类型的操作数的类型的所有值,则带有无符号整数类型的操作数将转换为带有有符号整数类型的操作数的类型。我猜测您的sizeof返回无符号长整型,其值可以由有符号整型表示,因此结果类型为有符号。 - Skurmedel
上面的部分解释了,如果无符号类型的秩(rank)等于或大于有符号类型的秩,那么有符号类型将被转换为无符号类型。也就是说,如果sizeof返回的是unsigned int,但是您的编译器可能会返回unsigned longs。 - Skurmedel

3
关于您提出的问题:
#define AA (-64)

请参见C预处理器中的宏定义和扩展

对象宏通常作为良好的编程实践的一部分使用,用于为常量创建符号名称,例如:

#define PI 3.14159

...而不是在代码中硬编码这些数字。然而,C和C ++都提供了const指令,提供了另一种避免硬编码常量的方法。

作为宏定义的常量没有关联的类型。尽可能使用const


1
回答你其中一个子问题: 要在宏中“定义常量”(这有点不严谨,你并没有定义“常量”,只是进行了一些文本替换的技巧),并且使其无符号,你应该使用'u'后缀:
#define UNSIGNED_FORTYTWO 42u

在你键入UNSIGNED_FORTYTWO的任何位置,这将插入一个unsigned int字面量。

同样地,在中经常看到使用后缀来设置精确的浮点类型:

#define FLOAT_PI 3.14f

这将在您在代码中键入FLOAT_PI的位置插入一个float(即“单精度”)浮点文字。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接