C 类型转换是字符*到整数*未定义吗?

C 类型转换是字符*到整数*未定义吗?,c,arrays,C,Arrays,我有一个打印字符数组内容的函数: #include <stdio.h> void print_array(char * array, int n) { char* start; for(start = array; start - array < n && printf("%d\n", *start); start++); } int main() { char array[5] = {'a', 'b', 'c', 'd', 'e'

我有一个打印字符数组内容的函数:

#include <stdio.h>

void print_array(char * array, int n) {
    char* start;

    for(start = array; start - array < n && printf("%d\n", *start); start++);
}

int main() {
    char array[5] = {'a', 'b', 'c', 'd', 'e' };
    print_array(array, 5);

    return 0;
}
如果我将函数更改为以下内容,则会出现问题:

void print_array(int * array, int n) {
    int* start;

    for(start = array; start - array < n && printf("%d\n", *start); start++);
}
这印的是垃圾

1684234849
101
1973473280
8388443
80884992

编译时,我打开了
-Wall
并没有发出警告。为什么我在键入指针时会收到垃圾?

int*
const char*
的转换定义良好

如果基础数据是
int[]
数组,则反之亦然,但不能将
const char*
指针指向的数组中的任意点转换为
int*
:您可能不遵守对齐要求


因此,在您的情况下,行为是未定义的,因为您从
char
数组开始

正如其他人所指出的,您的第二个实现是未定义的

正如其他人所说,由于您将数组的地址从(char*)强制转换为(int*),编译器假定您知道自己在做什么,并且不会抛出警告。尝试在没有强制转换的情况下编译以查看您的警告

现在,给你一个具体的例子来说明正在发生的事情(注意这个例子仍然是未定义的),考虑一下:

假设机器架构使用1字节表示字符,4字节表示整数

在代码中:

char array[5] = {'a', 'b', 'c', 'd', 'e' };
您分配了一个包含5个字符的数组。它们在内存中可能是这样的:

0x61 0x62 0x63 0x64 0x65
0x61626364 0x65?????? 0x???????? 0x???????? 0x????????
然后你打电话

print_array(array, 5);
在这种用法和上下文中,array实际上是指向&array[0]的隐式指针,即(char*)并指向0x61

现在在函数调用中,将数组强制转换为(int*)。您拥有的是一个由5个元素组成的数组,每个元素的宽度为1字节,它现在被解释(注意:未转换)为一个由(仍然)5个元素组成的数组,每个元素。。。4字节宽!在内存中可能是这样的:

0x61 0x62 0x63 0x64 0x65
0x61626364 0x65?????? 0x???????? 0x???????? 0x????????
在(int*)实现中,只定义了所需20个字节中的5个字节

根据机器的端度,第一个int可以解释为

  • 1684234849(little endian-参见上面的结果)
  • 1633837924(大端)
您已经注意到,打印时的其他4个元素是垃圾,因为我们不知道内存的内容

还请注意,您在第二个“int”元素上溢出了char[5]数组

同样,此示例依赖于体系结构且未定义。您可以在另一个体系结构上有完全不同的行为

编辑: 看起来很偶然,你的第二个“int”是

在little endian解释中:101就像你们在输出中看到的一样


但这是运气。它可以是任何垃圾。

是的,它未定义。还有其他问题吗?请注意,您也在边界外打印,以及所有其他类似的内容。@Someprogrammerdude-um-wat?在默认参数提升中,字符被提升为整数,因此除了可能的符号扩展之外,这里没有任何问题。。。“不过,几乎没有什么不确定的行为。”一些编程人员明目张胆地说。字符升级为整数或无符号整数,不存在不匹配。甚至标准也在printf文档中明确提到了这一点。
char*
是指针,而不是数组。@cᴏʟᴅsᴘᴇᴇᴅ: 我不这么认为。它写得很好,有一个很好的支持代码段。显而易见的问题不一定是坏问题,因为显而易见是主观的。大多数C语言的东西对Olaf来说是显而易见的,例如,从
int*
char*
的转换也是定义良好的吗?您指出
const char*
typecast有什么具体原因吗?@SebNag:绝对有!它必须是一个
常量字符*
。不遵守对齐要求只是一回事,打破严格的别名是第二位,而第三位(目前在普通计算机上大多是假设的)将是
int
@Bathsheba中的陷阱值让我解释一下。我为没有标出你的答案而道歉。但是,请看我做的标记的答案。我相信它非常清楚地解释了我输出的原因。@cᴏʟᴅsᴘᴇᴇᴅ: 没问题。我倾向于回避试图解释未定义的行为,因为这往往是徒劳的。实际上,最好的办法是检查生成的程序集。尽管如此,我的简短回答只触及了表面。
0x65000000