为什么采用 sizeof(array) 会在函数中发出警告,但在 main() 中却不会?
Why does taking sizeof(array) give warnings in a function, but not in main()?
我目前正在编写一些加密算法,但遇到了一个我无法理解的 GCC 编译错误。问题来了:
在我的 int main(void)
函数中,我得到了:
uint32_t block[2];
memset(block, 0x0, sizeof(block));
printf("%ld \n", sizeof(block));
这对于 GCC 来说还不错。
然后,我将这个名为 block
的 uint32_t 数组传递给一个函数:
void readOneBlockFromFile(int fd, uint32_t block[2]){
if(fd == -1){
perror("fd");
errno = EIO;
exit(errno);
}
int nb_bytes_read = 0;
while(1){
memset(block, 0x0, sizeof(block));
nb_bytes_read = read(fd, block, sizeof(block));
if(nb_bytes_read == -1){
perror("read");
exit(errno);
}
if(nb_bytes_read == 0){
break; //EOF
}
}
}
这里我收到一些 GCC 警告:
SPN.c: In function ‘readOneBlockFromFile’:
SPN.c:46:30: warning: ‘sizeof’ on array function parameter ‘block’ will return size of ‘uint32_t * {aka unsigned int *}’ [-Wsizeof-array-argument]
memset(block, 0x0, sizeof(block));
^
SPN.c:38:44: note: declared here
void readOneBlockFromFile(int fd, uint32_t block[2]){
^~~~~
SPN.c:47:43: warning: ‘sizeof’ on array function parameter ‘block’ will return size of ‘uint32_t * {aka unsigned int *}’ [-Wsizeof-array-argument]
nb_bytes_read = read(fd, block, sizeof(block));
^
SPN.c:38:44: note: declared here
void readOneBlockFromFile(int fd, uint32_t block[2]){
^~~~~
所以当我使用 block
而不使用 block[0]
或 *block
.
时,我的 GCC 会发出警告
我不明白为什么 GCC 会给我警告,因为我可以在 main 中做同样的事情而没有任何问题。
在您的函数标题中
void readOneBlockFromFile(int fd, uint32_t block[2])
您将 block
声明为大小为 2 的数组。但是,在 C 中,数组 总是 作为指向其第一个元素的指针传递。因此 sizeof
将 return 指针的大小,而不是数组的大小。
(本质上,声明您传递的数组的大小有助于编译器检查您的代码,是否传递了正确的参数。在 multi-demensional 数组中,编译器允许您使用 [][]
索引。如果不声明传递的数组的大小,那是不可能的。)
您似乎还知道数组的大小,因此将其传递给 read
,例如sizeof(uint32_t [2])
。
在我看来更有用的界面是:
int readOneBlockFromFile(int fd, void *block, int size)
{
int nb_bytes_read = read(fd, block, size);
//...
return nb_bytes_read;
}
int example(void)
{
uint32_t block[2];
if (readOneBlockFromFile(1,block,sizeof(block))==0) {
// EOF
}
}
支持 Paul Ogilive 的精彩回答:
来自 C11 标准 6.3.2.1
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
这是详尽的规则 - 以防数组被转换为指针以及何时不是。这里也是传给函数的时候数组转为指针的情况
-强调我的
我目前正在编写一些加密算法,但遇到了一个我无法理解的 GCC 编译错误。问题来了:
在我的 int main(void)
函数中,我得到了:
uint32_t block[2];
memset(block, 0x0, sizeof(block));
printf("%ld \n", sizeof(block));
这对于 GCC 来说还不错。
然后,我将这个名为 block
的 uint32_t 数组传递给一个函数:
void readOneBlockFromFile(int fd, uint32_t block[2]){
if(fd == -1){
perror("fd");
errno = EIO;
exit(errno);
}
int nb_bytes_read = 0;
while(1){
memset(block, 0x0, sizeof(block));
nb_bytes_read = read(fd, block, sizeof(block));
if(nb_bytes_read == -1){
perror("read");
exit(errno);
}
if(nb_bytes_read == 0){
break; //EOF
}
}
}
这里我收到一些 GCC 警告:
SPN.c: In function ‘readOneBlockFromFile’:
SPN.c:46:30: warning: ‘sizeof’ on array function parameter ‘block’ will return size of ‘uint32_t * {aka unsigned int *}’ [-Wsizeof-array-argument]
memset(block, 0x0, sizeof(block));
^
SPN.c:38:44: note: declared here
void readOneBlockFromFile(int fd, uint32_t block[2]){
^~~~~
SPN.c:47:43: warning: ‘sizeof’ on array function parameter ‘block’ will return size of ‘uint32_t * {aka unsigned int *}’ [-Wsizeof-array-argument]
nb_bytes_read = read(fd, block, sizeof(block));
^
SPN.c:38:44: note: declared here
void readOneBlockFromFile(int fd, uint32_t block[2]){
^~~~~
所以当我使用 block
而不使用 block[0]
或 *block
.
我不明白为什么 GCC 会给我警告,因为我可以在 main 中做同样的事情而没有任何问题。
在您的函数标题中
void readOneBlockFromFile(int fd, uint32_t block[2])
您将 block
声明为大小为 2 的数组。但是,在 C 中,数组 总是 作为指向其第一个元素的指针传递。因此 sizeof
将 return 指针的大小,而不是数组的大小。
(本质上,声明您传递的数组的大小有助于编译器检查您的代码,是否传递了正确的参数。在 multi-demensional 数组中,编译器允许您使用 [][]
索引。如果不声明传递的数组的大小,那是不可能的。)
您似乎还知道数组的大小,因此将其传递给 read
,例如sizeof(uint32_t [2])
。
在我看来更有用的界面是:
int readOneBlockFromFile(int fd, void *block, int size)
{
int nb_bytes_read = read(fd, block, size);
//...
return nb_bytes_read;
}
int example(void)
{
uint32_t block[2];
if (readOneBlockFromFile(1,block,sizeof(block))==0) {
// EOF
}
}
支持 Paul Ogilive 的精彩回答:
来自 C11 标准 6.3.2.1
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
这是详尽的规则 - 以防数组被转换为指针以及何时不是。这里也是传给函数的时候数组转为指针的情况
-强调我的