C 获取指向字符串常量的指针
C 获取指向字符串常量的指针,c,string,pointers,memory-management,c89,C,String,Pointers,Memory Management,C89,“BM”必须位于只读内存区域的某个位置,那么为什么我不能获取指向它的指针?(它进行编译,但表示内存区域无效(clang编译器))C不允许获取文本的地址: 一元&运算符的操作数应为函数指示符、[]或一元*运算符的结果,或指定非位字段且未使用寄存器存储类说明符声明的对象的左值 --C99 6.5.3.2/1 文字不属于任何允许的操作数类别。这是语言的一个正式约束——一致性实现不需要接受违反它的代码,而需要生成描述违反的诊断。C不定义违反约束的代码行为 您可以实现与您似乎想要的类似的目标: short
“BM”
必须位于只读内存区域的某个位置,那么为什么我不能获取指向它的指针?(它进行编译,但表示内存区域无效(clang编译器))C不允许获取文本的地址:
一元&
运算符的操作数应为函数指示符、[]
或一元*
运算符的结果,或指定非位字段且未使用寄存器
存储类说明符声明的对象的左值
--C99 6.5.3.2/1
文字不属于任何允许的操作数类别。这是语言的一个正式约束——一致性实现不需要接受违反它的代码,而需要生成描述违反的诊断。C不定义违反约束的代码行为
您可以实现与您似乎想要的类似的目标:
short var = *((unsigned short*)&"BM");
除其他外,这避免了将指针解引用到未对齐存储的风险。C将对齐变量
u
的存储,以便所有成员在适当的边界上对齐。这避免了您最初尝试的任何方法可能出现的陷阱。最简单的解决方案当然是:
union short_str {
char str[3];
int16_t sh;
} u = { "BM" };
short var = u.sh;
或
charvar=*((const char*)和“BM”)代码>在MSVC2012上编译。我认为这是一个很好的形式。我认为您的示例的行为是未定义的。它返回无效内存区域中的读取错误
,这意味着它试图访问不存在或受读取保护的内存地址。令人惊讶的是,它可以在MSVC2012上运行。int main(){char var=*((const char*)和“BM”);printf(“%c”,var);}
编译并在gcc 4.7.3上运行。行为未定义,因为地址不能保证可强制转换为指针类型。常量字符串的内存地址可能未对齐或位于只读内存中。您确定吗?您可以为其分配一个常量char*
,并将其用作printf中的%s参数。这在C89中合法吗?在我看来,这是一项创新。@Klaslindbkäck这是唯一一种不可携带但足够快的方式。另一种是显式转换(解决方案正在尝试的)。但是通过删除&
-只要将其分配给一个字符,它就可以工作。即short var=*((const short*)“BM”)代码>抛出警告。还有阿福。。在大多数情况下,警告应解释为错误。在C89中,初始值设定项是合法的。括号中的第一个元素用于初始化联合的第一个成员。如果括号中有多个初始值设定项,我不确定是否定义了语义。另外,请注意,从不同的联合成员(而不是上次写入的成员)读取包含实现定义的行为,但这是因为(void*)&u.str==(void*)&u.sh
,必须是真的,实际上,这种方法非常可靠。因为它是实现定义的(而不是未定义的),所以在您发现它很可能工作的情况下,您可以依靠它继续工作。
short var= 0x424D; // memory reads 4D, 42 = 'M', 'B'
short var= 0x4D42; // memory reads 42, 4D = 'B', 'M'