所以我在学习和练习C语言中变量的指针和地址的概念。但有一件事让我很好奇。我运行的代码是-
#include <stdio.h>
int main()
{
int *p, n;
p = &n;
int *c = NULL;
printf("Address of variable = %pn", p);
printf("Address of variable = %lun", p);
printf("Address of c variable = %lun", c);
return 0;
}
我确信这段代码是正确的打印地址,我得到的输出是-
pointer.c: In function ‘main’:
pointer.c:10:37: warning: format ‘%lu’ expects argument of type ‘long unsigned
int’, but argument 2 has type ‘int *’ [-Wformat=]
10 | printf("Address of variable = %lun", p);
| ~~^ ~
| | |
| | int *
| long unsigned int
| %ls
pointer.c:11:39: warning: format ‘%lu’ expects argument of type ‘long unsigned
int’, but argument 2 has type ‘int *’ [-Wformat=]
11 | printf("Address of c variable = %lun", c);
| ~~^ ~
| | |
| | int *
| long unsigned int
| %ls
Address of variable = 0x7fffc5a57474
Address of variable = 140736509342836
Address of c variable = 0
所以,我想知道这些编译器警告是什么意思,我应该关心这些警告吗?
另外,当我使用%d
而不是%p
或%lu
时,我得到的地址值为"负的";值,那么内存中是否可以存在负地址?
此外,输出中的地址值异常大。它们甚至比我的16gb RAM的大小还要大,我的变量怎么可能存储在一个不存在的位置?
如果您将指针视为数字,则必须小心。在内部,它们通常是地址,它们通常是数字,但它们是无符号数字。所以,不,你通常不会有"否定地址"。
你可能还没有学过计算机是如何表示负数的。下面是常见的"二互补"的快速演示。表示,只使用三个比特。关键是相同的位模式可以有两种不同的解释,这取决于您是否关心负值:
signed int
unsigned int
您的代码不正确。
转换说明符lu
期望其对应的实参类型为unsigned long
,d
期望其对应的实参类型为int
;p
和c
的类型为int *
,因此有警告。是的,这些警告很重要——至少您会得到乱码的输出,正如您已经发现的那样。
指针类型不是整型;它们不必具有与整数类型相同的大小或表示(在x86_64上,int
是32位宽,但指针类型是64位宽)。唯一为指针类型定义的转换说明符是p
,它期望其对应的实参类型为void *
。
printf( "p = %pn", (void *) p );
printf( "c = %pn", (void *) c );