![](/img/trans.png)
[英]What actually happens when a pointer to integer is cast to a pointer to char?
[英]What happens when you type cast an integer value into a char pointer?
例如,
char * integerToString(void);
int main() {
char *myString;
do {
myString = integerToString();
} while (myString == (char *)-1); // worked as intended
free(myString);
return 0;
}
char * integerToString(void) {
int userInput;
printf("Enter an integer: ");
scanf("%d", &userInput);
if (userInput < 0 || userInput > 99)
return (char *)-1; // what happens here?
char *myString = (char *)malloc(sizeof(char) * 2);
myString[0] = (int)floor(userInput/10.0) + '0';
myString[1] = userInput%10 + '0';
return myString;
}
并且该程序按预期工作,但是当您键入将整数值(不将整数分配给变量)时,将其完全转换为字符指针会发生什么? 这个程序会一直有效吗? 谢谢。
C99:
6.3.2.3指针
- 值为0的整数常量表达式,或强制类型为
void *
的表达式,称为空指针常量 。 如果将空指针常量转换为指针类型,则保证生成的指针(称为空指针 )可以将不相等的指针与指向任何对象或函数的指针进行比较。[...]
- 整数可以转换为任何指针类型。 除非先前指定,否则结果是实现定义的,可能未正确对齐,可能未指向引用类型的实体,并且可能是陷阱表示。
因此,将-1
强制转换为指针具有实现定义的结果。 因此,答案是否定的:这不能保证总体上可行。
特别是:如果确实是陷阱表示,则您的代码将与以下内容发生冲突:
6.2.6类型的表示
6.2.6.1概述
[...]
- 某些对象表示形式不必表示对象类型的值。 如果对象的存储值具有这种表示形式,并且由不具有字符类型的左值表达式读取,则该行为是不确定的。 如果这样的表示是由副作用产生的,该副作用通过不具有字符类型的左值表达式修改对象的全部或任何部分,则该行为是不确定的。 这样的表示称为陷阱表示 。
即while (myString == (char *)-1);
如果myString
是陷阱表示,则具有未定义的行为。
当您键入将整数值转换为char指针时会发生什么?
通常,这是未定义的行为 (至少在取消引用后立即执行)。 要非常害怕 。 阅读有关UB的更多信息(这是一个棘手的主题)。
在某些记录的情况下,您可以将uintptr_t
或intptr_t
整数值放入有效的指针中。
在您的情况下,您分配给堆的字符串太短(因此,您有一个缓冲区溢出 ,这是UB的许多示例之一)。 您忘记了终止NUL字节的空间,并且忘记了检查malloc
失败。 顺便说一句, sizeof(char)
始终为 1。
您可以编写以下代码:
if (userInput < 0 || userInput > 99)
return NULL;
char *myString = (char *)malloc(3);
if (!myString) { perror("malloc myString"); exit(EXIT_FAILURE); };
myString[0] = (int)floor(userInput/10.0) + '0';
myString[1] = userInput%10 + '0';
myString[2] = (char)0;
return myString;
在大多数系统(但不是全部)上, (char*)-1
永远不是有效地址(总是在虚拟地址空间之外 ),并且永远不能由系统(或标准)功能给出。 在我的Linux / x86-64桌面上,我知道 (char*)-1
不是有效的地址(例如,因为它是MAP_FAILED
),所以我(有时)可以将其用作前哨非空指针值(该值应该不要取消引用)。 但这使我的代码不那么可移植 。
因此,您可以决定并记录您的integerToString
在非整数输入上给出(char*)-1
,而在堆分配失败上给出NULL
。 那可以在我的Linux / x86-64桌面上工作(所以有时我可以这样做)。 但这不是纯(便携式)C11代码。
但是,如果您坚持使用C11标准(读取n1570 ),则它是实现定义的内容,并且(char*)-1
是否有意义。 甚至可能是某些陷阱表示形式甚至不允许您进行比较(即使我不知道这样做的实际C实现)。
实际上,您的示例说明人们从来没有为纯标准C11编写代码 ; 他们总是(我也是)对C的实现做出其他假设 ; 但是您确实需要意识到它们 ,这些假设可能会使将代码移植到某些假设的未来机器上的噩梦。
这个程序会一直有效吗?
这是一个太笼统的问题。 您的原始程序甚至没有处理malloc
失败,并且有缓冲区溢出 (因为您忘记了终止零字节的空间)。 但是,对您来说可悲的是,它似乎通常似乎可以工作(这就是UB 如此恐怖的原因)。 但是, 将此 malloc
实现(符合标准但不切实际的)视为malloc
深思的。
(确切解释为什么程序看起来像您想要的那样非常困难,因为您需要深入研究几个实现细节)
该程序是错误处理错误的一个示例。 (char *)-1
似乎是实现定义的,请参见其他答案。 由于此地址可能不是从malloc
返回的有效内存地址,因此在程序中将其用作标记值 。 实际值无关紧要,将其与其他函数中的相同表达式进行比较。
如果运行此命令,则malloc
可能会返回(char *)-1
求值的任何值。 尽管它是一个有效的内存地址,但它将被解释为错误。
更好的方法是为int *
类型的integerToString
提供参数, integerToString
其用作指示失败的布尔值。 这样一来,就不会为错误处理保留一个char *
值。
或使用C ++和一个例外。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.