使用 gcc 编译 c 程序时的警告消息

Thi*_*mar 6 programming compiling gcc

我是 linux 新手。我gcc在 Ubuntu 12.04 LTS 上使用(Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3。当我使用指针编译 c 程序时,我收到-Wformat如下所示的警告。但是如果我执行a.out文件,我会得到正确的结果。谁能告诉我为什么我收到这条消息并建议我应该怎么做才能克服?

我的测试程序:

 #include<stdio.h>

void main(void)

{

int x=10,y,z;
int *p=&x ;

        printf("\n\np  = %u\n",p);
        printf("\n*p = %u\n",*p);
        printf("\n&x = %u\n",&x);
        printf("\n&y = %u\n",&y);
        printf("\n&z = %u\n",&z);
        printf("\n&p = %u\n\n",&p);
}
Run Code Online (Sandbox Code Playgroud)

输出:

qust1-Array.c:11:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:14:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:15:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:16:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:17:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int **’ [-Wformat]
Run Code Online (Sandbox Code Playgroud)

con*_*use 5

由于你所得到的警告使用了错误的格式说明printf()p是一个整数指针。&p是指针的地址。&x&y是整数的地址。这些都是内存中的地址,而不是变量的值。说明符%u用于无符号整数的值。所以你在编译器需要橙子的地方打印苹果。地址比存储在变量中的某些值短。通过使用%u实际上会将地址值打印为十进制(非常不寻常)以及位于内存中的更多数据。编译器在抱怨,因为这可能不是您想要做的。要打印地址,请使用说明符%p,如下所示:

printf("\n&x = %p\n",&x);
Run Code Online (Sandbox Code Playgroud)

除此之外,您的变量是有符号整数,因此应使用%i代替%u。的%u格式说明符printf()仅适用于正整数。对于小的正值,%i%u可以互换。显示警告是因为变量类型与其说明符不匹配,这在某些情况下会导致问题。

从您的变量类型来看,这会更明智:

printf("\n\np  = %p\n",  p); // p is a pointer so %p would print the address

printf("\n*p = %i\n",   *p); // the data saved at that address is an integer 
                             // so %i is appropriate if you dereference the 
                             // pointer with the star "*p"

printf("\n&x = %p\n",   &x); // &x gives the address of the integer variable x 
                             // so %p is the specifier for that address

printf("\n&y = %p\n",   &y);
printf("\n&z = %p\n",   &z);

printf("\n&p = %p\n\n", &p); // &p gives the address, where the pointer p is 
                             // stored -> still an address -> %p is the right
                             // specifier
Run Code Online (Sandbox Code Playgroud)

关于有符号和无符号整数和指针的一些背景知识:

C 使用相同的 32 位(或另一种 2 的幂,取决于系统架构)来存储无符号和有符号整数。因此最高值unsigned int是 2 32 -1 或二进制表示法:

2 32 -1 = (111111111111111111111111111111111) 2 <- (无符号)

数字一在二进制中看起来像这样:

       1 = (00000000000000000000000000000001) 2 <- (无符号)

现在常规有符号整数也需要存储负数,但仍然在相同的 32 位空间中。如果您将数字的符号存储在例如第一位中,您将丢失一整位。那会很浪费,例如零将有两种表示形式,即 + 和 - 零。为了规避这个问题,有符号整数中的负数存储方式略有不同:要将数字编码为有符号整数,请将 32 位数字的可能范围减半。这是 2 (32-1),然后使用该新数字的常规二进制表示。所以一个 1 被编码为 2 (32-1) + 1 将是一个无符号整数。我们有:

 2 (32-1) = (111111111111111111111111111111111) 2 <-签名

         ...

         1 = (10000000000000000000000000000001) 2 <- 签名

         0 = (10000000000000000000000000000000) 2 <- 签名

        -1 = (01111111111111111111111111111111) 2 <- 签名

         ...

-2 (32-1) = (00000000000000000000000000000000) 2 <-签名

现在您已经编码了相同数量的整数,但有符号整数的最大值因此只有 2 (32-1),而不是无符号整数的两倍,2 32 -1。这称为负数的过量 K偏移二进制表示。大多数系统使用二进制补码,其中第一个最重要的位被反转。

要查看此内容,请设置x=-1;然后printf("%u",x)。您将获得以下输出:

2147483648

这是 2 32-1或 (011111111111111111111111111111111) 2二进制表示法。对于 2 的补码,这个数字是:

4294967295

或 2 32 -1。这在二进制中等于 (11111111111111111111111111111111) 2,因此与上面的 2147483648 的超量 K 值相比,它的第一位反转。

因此,这是如何将数据存储。当您想到where时,指针就会发挥作用。内存中的物理位必须有地址。由于它们中的数量令人难以置信,因此您可以分块地解决它们。如果创建一个指针,指针地址处的物理内存将保存内存中的另一个地址。所以房子是一个物理对象,很像你电脑内存中的一点。一张纸就是一个指针。它比房子小,但可以保存房子或其他房子的地址。在那个比喻中,上面你会试图拆除一张纸而不是实际的房子,它实际上是一座山......

  • 一个冗长的解释,但错误。实际问题是格式说明符用于无符号整数,但参数是指针(或数组,或指向指针的指针,如果您愿意)。 (2认同)