user-0 提问: 关于指向常量的指针

回复:
user: user-1
content: 理解和讨论之前请先观察！

user: user-1
content: 汇编指令也有地址！  电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……

user: user-2
content: 2是个值,不是变量,不能对值取地址, 要对变量取地址

user: user-1
content: 2放在汇编指令里，不一定没有地址。只不过这个代码段中的地址几乎没人用它罢了。

user: user-1
content: 电脑内存或文件内容只是一个一维二进制字节数组及其对应的二进制地址； 人脑才将电脑内存或文件内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息……  其实电脑开机后物理内存的每个字节都是可读写的，区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页，一页通常为4KB。

user: user-1
content: #pragma comment(linker,"/SECTION:.text,RW") //上面这句让代码段可写 #include <stdio.h> int *p; int p2() {     int a;      a=2;     return a; } int main() {     p=(int *)((char *)p2+0x0C);     printf("p2==0x%08x,p==0x%08x,*p==%d\n",(char *)p2,p,*p);     *p=3;     printf("p2()==%d\n",p2());     return 0; } //p2==0x00401000,p==0x0040100c,*p==2 //p2()==3 //

user: user-1
content: 1:    #include <stdio.h> 2:    int *p; 3:    void p2() { 00401000 55                   push        ebp 00401001 8B EC                mov         ebp,esp 00401003 83 EC 44             sub         esp,44h 00401006 53                   push        ebx 00401007 56                   push        esi 00401008 57                   push        edi 4:        int a; 5: 6:        a=2; 00401009 C7 45 FC 02 00 00 00 mov         dword ptr [ebp-4],2 7:    } 00401010 5F                   pop         edi 00401011 5E                   pop         esi 00401012 5B                   pop         ebx 00401013 8B E5                mov         esp,ebp 00401015 5D                   pop         ebp 00401016 C3                   ret --- No source file  --------------------------------------------------------------------------- 00401017 CC                   int         3 00401018 CC                   int         3 00401019 CC                   int         3 0040101A CC                   int         3 0040101B CC                   int         3 0040101C CC                   int         3 0040101D CC                   int         3 0040101E CC                   int         3 0040101F CC                   int         3 8:    int main() { 00401020 55                   push        ebp 00401021 8B EC                mov         ebp,esp 00401023 83 EC 40             sub         esp,40h 00401026 53                   push        ebx 00401027 56                   push        esi 00401028 57                   push        edi 9:        p=(int *)((char *)p2+0x0C); 00401029 B8 00 10 40 00       mov         eax,offset p2 (00401000) 0040102E 83 C0 0C             add         eax,0Ch 00401031 A3 20 30 40 00       mov         [p (00403020)],eax 10:       printf("p2==0x%08x,p==0x%08x,*p==%d\n",(char *)p2,p,*p); 00401036 8B 0D 20 30 40 00    mov         ecx,dword ptr [p (00403020)] 0040103C 8B 11                mov         edx,dword ptr [ecx] 0040103E 52                   push        edx 0040103F A1 20 30 40 00       mov         eax,[p (00403020)] 00401044 50                   push        eax 00401045 68 00 10 40 00       push        offset p2 (00401000) 0040104A 68 A4 20 40 00       push        offset string "p2==0x%08x,p==0x%08x,*p==%d\n" (004020a4) 0040104F FF 15 00 20 40 00    call        dword ptr [__imp__printf (00402000)] 00401055 83 C4 10             add         esp,10h 11:       return 0; 00401058 33 C0                xor         eax,eax 12:   } 0040105A 5F                   pop         edi 0040105B 5E                   pop         esi 0040105C 5B                   pop         ebx 0040105D 8B E5                mov         esp,ebp 0040105F 5D                   pop         ebp 00401060 C3                   ret //p2==0x00401000,p==0x0040100c,*p==2 //  1:    #include <stdio.h> 2:    int *p; 3:    void p2() { 00401000 55                   push        ebp 00401001 8B EC                mov         ebp,esp 00401003 83 EC 44             sub         esp,44h 00401006 53                   push        ebx 00401007 56                   push        esi 00401008 57                   push        edi 4:        int a; 5: 6:        a=2; 00401009 C7 45 FC 02 00 00 00 mov         dword ptr [ebp-4],2 7:    } 00401010 5F                   pop         edi 00401011 5E                   pop         esi 00401012 5B                   pop         ebx 00401013 8B E5                mov         esp,ebp 00401015 5D                   pop         ebp 00401016 C3                   ret --- No source file  --------------------------------------------------------------------------- 00401017 CC                   int         3 00401018 CC                   int         3 00401019 CC                   int         3 0040101A CC                   int         3 0040101B CC                   int         3 0040101C CC                   int         3 0040101D CC                   int         3 0040101E CC                   int         3 0040101F CC                   int         3 8:    int main() { 00401020 55                   push        ebp 00401021 8B EC                mov         ebp,esp 00401023 83 EC 40             sub         esp,40h 00401026 53                   push        ebx 00401027 56                   push        esi 00401028 57                   push        edi 9:        p=(int *)((char *)p2+0x0C); 00401029 B8 00 10 40 00       mov         eax,offset p2 (00401000) 0040102E 83 C0 0C             add         eax,0Ch 00401031 A3 20 30 40 00       mov         [p (00403020)],eax 10:       printf("p2==0x%08x,p==0x%08x,*p==%d\n",(char *)p2,p,*p); 00401036 8B 0D 20 30 40 00    mov         ecx,dword ptr [p (00403020)] 0040103C 8B 11                mov         edx,dword ptr [ecx] 0040103E 52                   push        edx 0040103F A1 20 30 40 00       mov         eax,[p (00403020)] 00401044 50                   push        eax 00401045 68 00 10 40 00       push        offset p2 (00401000) 0040104A 68 A4 20 40 00       push        offset string "p2==0x%08x,p==0x%08x,*p==%d\n" (004020a4) 0040104F FF 15 00 20 40 00    call        dword ptr [__imp__printf (00402000)] 00401055 83 C4 10             add         esp,10h 11:       return 0; 00401058 33 C0                xor         eax,eax 12:   } 0040105A 5F                   pop         edi 0040105B 5E                   pop         esi 0040105C 5B                   pop         ebx 0040105D 8B E5                mov         esp,ebp 0040105F 5D                   pop         ebp 00401060 C3                   ret //p2==0x00401000,p==0x0040100c,*p==2 //

user: user-3
content: 关键在于 2和 "abcd" 的存储所在的段位置是不同的我理解    一个是栈段     一个是bss 我猜的

user: user-4
content: 一元 & 运算符要求操作数是左值  2不用是左值 然后就死了

user: user-5
content: 引用 2 楼 jerry_dqh 的回复:最直接的讲就是这个语法规定的，但是为啥语法这样规定呢？ 2这个值放在哪儿，你知道吗？编译不会将2放在内存中，所以无法取址。 但:abcd不一样，其是放在静态数据区的。  不能对常量使用 & 操作符

user: user-6
content: 跟存放位置没有关系，是左值右值的问题，在C/C++中，字符串常量是左值（原理上可左可右），而其他常量是右值。你可以看看编译器的报错情况，这个是有提示的，VS下是说对象必须是左值或函数指示符（函数指示符记得再C中非左值也非右值，你可以在这里了解下），而g++下是taking address of temporary ，因为右值就是临时的，而取临量的地址是非常危险的，所以被禁止了。  如果是C++的话，你可以试下cout<<&string("123"); g++中是会报错的，但cout<<&"123";就不会。不过VS下两者都不会报错，可能是实现上统一了吧。原理上string("123")应该算是一个右值，具体可以看看这篇文章，说的很详细了。

user: user-7
content: 既然整个字符串无法放在存放在机器指令里,只能放在内存空间里,存取访问. 那么字符串在内存中存放的地址,可以放到汇编指令中. 所以 char *s="abcd" 编译成汇编指令就是  mov         dword ptr [s],offset string "abcd" (417840h)   所以就把字符串在内存中存放的地址417840h,放在机器指令中.这个地址是固定的.

user: user-8
content: 最直接的讲就是这个语法规定的，但是为啥语法这样规定呢？ 2这个值放在哪儿，你知道吗？编译不会将2放在内存中，所以无法取址。 但:abcd不一样，其是放在静态数据区的。

user: user-7
content: 这个问题问得好,我以前也想过 因为2可以直接写在汇编指令里,也就是放在机器指令里了.既然放在机器指令里,也就没有什么地址而言了.但是字符串就不同了,整个字符串无法放在存放在机器指令里,只能放在内存空间里,存取访问. 比如 int a=2; 编译成汇编指令就是 mov         dword ptr [a],2