在学校,我们必须编写一个小程序,它应该查看文件的前2个字节,以检查它是否应该像JPEG文件一样启动。 (这是一个UNIX初学者课程)
一个小组提供了以下解决方案(删除了错误处理):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char** argv) {
int fd = open(argv[1], 0);
unsigned char buffer[2];
ssize_t readBytes = read(fd, &buffer, 2);
if(buffer[0] == 0xFF && buffer[1] == 0xD8) {
printf("The file starts with a JPEG header\r\n");
} else {
printf("The file does not start with a JPEG header\r\n");
}
}
它编译时没有任何警告(即使使用-Wincompatible-pointer-types)并按预期工作,但不是我期望的那样。
我已经了解到,至少在C ++中,数组实际上只是指向数组第一个元素的指针,使用array[index]
语法实际上只是*(array+index)
所以我编译了这个版本的程序,还有一个,我只使用buffer
,因为我希望它是数组地址,因此read
需要什么。事实证明,这两个程序在反汇编时看起来完全相同。
那么这里发生了什么?我一直在与同事讨论这个问题,我们猜测这是因为数组实际上只是堆栈中的一些空间,它将在编译期间静态分配,因此编译器将在使用buffer[index]
的地方使用静态地址。因此,为了模拟在堆存储中动态分配的数组,GCC使用buffer[0]
的地址,只使用buffer
。但为什么&buffer
甚至会成为合法的语法?
这件事让我很困惑,我真的很想知道这里发生了什么。
答案 0 :(得分:1)
我已经了解到,至少在C ++中,数组实际上只是指向数组第一个元素的指针
完全没有。数组是一种与指针不同的类型。
数组的地址与其第一个元素的地址一致,并且数组隐式地将(衰减)转换为指向其第一个元素的指针,因此array == &array[0] == array + 0
。
从数组类型的左值和右值到指针类型的右值有一个隐式转换:它构造一个指向数组第一个元素的指针。只要数组出现在不需要数组的上下文中,就会使用此转换,但指针是。