如果我用字符串实例化一个int,那个int的值实际上是什么? 例如对于以下代码:
#include <stdio.h>
int main(void) {
int a = "abcd";
printf("a as string witn & = %s\n", &a);
printf("a as int witn no & = %d\n", a);
printf("a as int witn & = %d\n", &a);
}
我得到的每个执行的值都不同,例如:
a as string witn & = "?????W?
a as int witn no & = 130694946
a as int witn & = 1475726188
或
a as string witn & = "?O?Kp\?
a as int witn no & = 55557922
a as int witn & = 1550863212
这些价值观是什么?为什么他们总是不同?什么是'a'实际存储?
答案 0 :(得分:10)
int a = "abcd";
这在C中是非法的。
好吧,有点儿。对于这种事情,C标准实际上并没有使用“非法”一词。准确地说,它是约束违规,这意味着任何符合标准的编译器必须发出诊断消息(可能是非致命警告)。表达式"abcd"
是一个数组表达式,类型为char[5]
(字母为4,终止\0'
为1)。在大多数情况下,包括这个(如果它是有效的),数组表达式被隐式转换为指向数组的第一个元素的指针。转换后,该值的类型为char*
,它是指向'a'
的指针。
从char*
到int
没有隐式转换,这就是初始化无效的原因。您可以添加强制转换,这是显式转换:
int a = (int)"abcd";
这将存储在a
字符串的内存地址中,从char*
转换为int
。在许多系统中,这种转换虽然合法,却会产生垃圾;例如,在我输入的系统上,char*
为64位,int
仅为32位。
C语言的旧版本(1989年之前)的编译器对隐式转换更加宽松,通常允许将整数和指针分配给彼此。更现代的编译器,即使他们要求他们诊断出这个错误,也可能(或可能不会)生成执行隐式转换的代码。 (严格地说,行为是未定义的,但隐式转换很常见。)
如果您的编译器拒绝
int a = "abcd";
它正在做它的工作。如果它只是警告你,就C标准来说,它仍然在做它的工作,但它实际上并没有通过产生隐式转换给你任何好处。
底线:分配给a
的值是垃圾,如果你的编译器没有抱怨它,找出你需要做什么选项来实现它。
至于printf
来电的输出:
printf("a as string witn & = %s\n", &a);
%s
需要一个指向字符串的char*
参数。 &a
的类型为int*
,并未指向字符串。行为未定义。最有可能printf
将从a
开始打印垃圾字节,直到碰巧遇到空字节(或崩溃)。
不要那样做。
printf("a as int witn no & = %d\n", a);
如果您的程序此时尚未崩溃,则会打印a
的值。该值是垃圾,通常可能是字符串文字地址的转换值,或者只是该地址的低32位。
printf("a as int witn & = %d\n", &a);
%d
需要int
类型的参数。 &a
的类型为int*
。未定义的行为。此可能以{十进制整数形式打印a
的内存地址。不要那样做。如果您确实要打印a
的地址,正确的方法是:
printf("&a = %p\n", (void*)&a);
答案 1 :(得分:0)
回答这个问题的最有效方法可能是漫游问题代码:
#include <stdio.h>
int main(void) {
int a = "abcd";
上面的行声明了一个名为a的int,并使用字符串“abcd”的地址初始化a。这一行将导致编译器变得有点脾气暴躁,因为它会抱怨类似:warning: initialization makes integer from pointer without a cast
。
printf("a as string witn & = %s\n", &a);
上述行的对象似乎是打印字符串。不幸的是,&a
是变量存储在内存中的内存地址,在您的系统中看起来像1550863212
或0x93E6DF1
。该值不是ASCII或UTF-8字符串;因此它似乎打印出垃圾:"?????W?
,"?O?Kp\?
或其他一些无意义的字符串,具体取决于a
的地址恰好是什么。当然,这条线会让编译器变得更加脾气暴躁; format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int *’
printf("a as int witn no & = %d\n", a);
上述行尝试将a
的值打印为有符号整数。它也会显得无意义,因为a
的值是字符串“abcd”的地址。因此,a
(作为有符号整数)的值将是字符串“abcd”存储在内存中的地址的有符号整数表示。
printf("a as int witn & = %d\n", &a);
上述行尝试将a
的内存地址打印为有符号整数。和其他人一样,这很可能再次出现在废话中。
printf("a as a string[%s]\n", a);
为了您的观赏乐趣,我添加了上面一行,输出:“a as a string[abcd]
”。这证明变量a
已成功初始化,尽管(再次)编译器认为我们疯了:warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
}