'char*`和'int'之间的语义不同*`

'char*`和'int'之间的语义不同*`,c,pointers,C,Pointers,我想知道为什么在C中声明和分配char*与int*具有不同的语义 以下所有代码都是使用标志-Wall-Werror-std=gnu99--pedantic用clang编译的。 我正在试图了解这种差异是否是真实存在的,或者在int*和char*之间是否存在更大的差异,我还没有意识到这一点 //这将编译 int main(int argc,const char*argv[]{ char*a; a=“1”; printf(“a:%s\n”,a); 返回退出成功; } //这将不会编译。这是一个并行结

我想知道为什么在C中声明和分配
char*
int*
具有不同的语义

以下所有代码都是使用标志
-Wall-Werror-std=gnu99--pedantic
clang
编译的。 我正在试图了解这种差异是否是真实存在的,或者在
int*
char*
之间是否存在更大的差异,我还没有意识到这一点

//这将编译
int main(int argc,const char*argv[]{
char*a;
a=“1”;
printf(“a:%s\n”,a);
返回退出成功;
}
//这将不会编译。这是一个并行结构,用char代替int
#包括
#包括
int main(int argc,const char*argv[]{
int*a;
a=1;
printf(“a:%d\n”,a);
返回退出成功;
}
//但这将编译
#包括
#包括
int main(int argc,const char*argv[]{
int*a;
int b=1;
a=&b;
printf(“a:%d\n”,*a);
返回退出成功;
}
其要点:

“1”
的数据类型是
char*
。因此,您将
char*
赋值给
char*
变量


1
的数据类型为
int
。因此,您正在将
int
赋值给
int*
变量,该变量由于类型不匹配而无法工作。

第二个示例无法编译,因为您启用了-Werror,并且您正试图将整数赋值给一个没有强制转换的指针,这通常只是一个警告。如果你做了
char*a;a='a'因为您将尝试为char*分配一个char

指针类型之间的语义不同——内存中作为指针存储的内容可能不会不同,但指针类型会影响编译。主要涉及指针算法、数组索引和使用指针聚合(结构)类型和函数

当您开始使用指针算术/数组索引时,情况就不同了。例如:

int value = 4
char *charp = &value;
int* intp = &value;

这两个都是有效的指针。如果使用函数指针(可以使用函数调用语法)和结构指针(可以使用
->
运算符访问引用结构的成员),则在编译过程中还将看到不同的行为。

处理数组、指针和标量语义之间的差异

除非它是
sizeof
或一元
&
运算符的操作数,或者是用于初始化声明中字符数组的字符串文字,否则“T
的N元素数组”类型的表达式将被转换(“衰减”)为“指向
T
的指针”类型的表达式,表达式的值将是数组第一个元素的地址

字符串literal
“1”
是类型为
char[2]
的数组表达式。在此上下文中,它“衰减”为
char*
类型的表达式,表达式的值是字符串第一个字符的地址。因此,您正在分配“喜欢”到“喜欢”:

 a = "l"; // char * = char *
整数变量不会发生这种情况。文本
1
具有类型
int
,但您正试图将该
int
值分配给
int*
对象:

a = 1; // int * = int 
这将触发诊断。只能将
int*
值分配给
int*
对象-需要显式强制转换
1

a = (int *) 1; 

这将抑制诊断,但
1
很可能不是您平台上的有效内存地址,尝试使用它将导致问题

区别不是在
char*
int*
之间,而是在
“1”
1
之间;a=“1”将
a
设置为字符串literal
“1”
的地址。我马上想到的主要区别是指针算法和数组索引
((char*)a)[5]
((int*)a)[5]
的位置不同,因此区别在于字符串文字“1”本身是一个引用,而整数文字1是一个值。可能有更确切的方式来表达这个短语。为了完整性,也要考虑<代码>‘a’/COD>一个字符,它像你的int,<代码> char s[] =“hello”<代码>一个数组中的字符串,<代码> int a[] = {1,2,3,4} < /代码>,这两个指针的指针都是相同的,而你的例子是好的,对于新手来说,这也有点像一个陷阱。为什么?因为它只在这个星座是合法的;如果您有
char值=4您将违反第三行的严格别名规则。也许你想在这方面扩大你的答案。