关于复制垃圾
On Copying Garbage
几天前,我在这里进行了一次关于复制的小讨论,我们称它为垃圾,因为这就是从一个数组到另一个数组的实际情况,如果在标准 C (ISO/IEC 9899-2011) 中是否可以接受。
为清楚起见,包含在一些示例代码中:
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 10
/*
? = any byte with ('?' != '?' || '?' == '?'), that is: '?' may or may not be equal to '?'.
tl;dr: just random garbage
'x' = a one byte large (not necessary ASCII-encoded) known and defined character.
tl;dr: neither random nor garbage
*/
int main(){
// array = [?,?,?,?,?,?,?,?,?,?]
char array[ARRAY_SIZE];
// copy = [?,?,?,?,?,?,?,?,?,?]
char copy[ARRAY_SIZE];
int i;
// fill a part of "array" with a NUL terminated string
// "part" is not necessary half+1 of it, the only condition is: #part < ARRAY_SIZE
// such that we have at least one byte of garbage
for(i = 0;i < ARRAY_SIZE/2;i++){
// casting "i" is a bit "holier than the pope", admitted
array[i] = (char)i + '0';
}
array[i] = '[=10=]';
// array = ['0','1','2','3','4','[=10=]',?,?,?,?]
// "use" the array "array"
printf("array = %s\n",array);
// copy all of the elements of "array" to "copy" including
// the garbage at the end
for(i = 0;i < ARRAY_SIZE;i++){
copy[i] = array[i];
}
// copy = ['0','1','2','3','4','[=10=]',?,?,?,?]
// "use" the array "copy"
printf("copy = %s\n",copy);
// no further use of either "array" or "copy".
// obvious at the end of main() but meant generally, of course
exit(EXIT_SUCCESS);
}
标准中定义这些数组的段落在派生类型列表中:
6.2.5 Types
20 Any number of derived types can be constructed from the object and
function types, as follows:
- An array type describes a contiguously allocated nonempty set
of objects with a particular member object type, called the element type.
The element type shall be complete whenever the array type is specified.
Array types are characterized by their element type and by the number of
elements in the array. An array type is said to be derived from its
element type, and if its element type is T, the array type is sometimes
called "array of T". The construction of an array type from an element
type is called "array type derivation".
我的问题是:"nonempty set" 是否只是意味着声明中的 n
(其中 n
代表整数文字;它与 VLA 无关)T a[n]
必须大于零?
对于那些需要实际原因的人:在实时领域,明确定义的操作数量优于未知数量。由于必要的测量,它在大部分时间(假设输入的随机分布)也较慢,并且这种开销在嵌入区域中很重要。当电池需要保持足够的电量以 运行 几年时,每节省纳安安时就很重要。
是的,这意味着 ARRAY_SIZE 必须大于零。
在这个级别,您可能应该将优化留给编译器。
但是如果 ARRAY_SIZE 是一个定义的常量,您可以通过一个数组进行优化,该数组的元素大小与您的 CPU 寄存器相同。您的数组大小应该是寄存器大小的整数倍。
要进行更多优化,您应该深入研究汇编程序输出。
如果代码读取没有陷阱表示的类型的不确定值,标准对于保证或不保证什么是模糊的。如果一个类型有任何陷阱表示并且代码试图读取该类型的不确定值,则读取的值可能是陷阱表示,从而导致读取调用未定义的行为。但是,如果该类型没有任何陷阱表示,事情就不太清楚了。
要求代码不能复制数组元素,除非它已经初始化它,即使元素的类型没有陷阱表示,即使没有人关心副本的值,也会降低效率可以表达许多算法。另一方面,给出类似的东西:
struct fnord { unsigned char q; ... }
struct fnord x=foo[i];
doSomething(x.q);
...
doSomething(x.q);
不清楚是否需要编译器来确保相同的
在 foo[i]
持有不确定值的情况下,值将传递给两个函数调用。结构不允许有陷阱表示(unsigned char
以外的类型的成员可能,但复制整个结构是定义的行为,即使某些成员的底层存储持有其类型的陷阱表示)。另一方面,对 x
的写入可能被视为导致 x
持有不确定值,因此对 doSomething
的调用可能会收到不同的值。
如果标准指定了一种方法,可以读取没有陷阱表示的类型的不确定值以产生未指定的值,那将非常有帮助,但我不知道标准中有任何此类规范。
几天前,我在这里进行了一次关于复制的小讨论,我们称它为垃圾,因为这就是从一个数组到另一个数组的实际情况,如果在标准 C (ISO/IEC 9899-2011) 中是否可以接受。
为清楚起见,包含在一些示例代码中:
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 10
/*
? = any byte with ('?' != '?' || '?' == '?'), that is: '?' may or may not be equal to '?'.
tl;dr: just random garbage
'x' = a one byte large (not necessary ASCII-encoded) known and defined character.
tl;dr: neither random nor garbage
*/
int main(){
// array = [?,?,?,?,?,?,?,?,?,?]
char array[ARRAY_SIZE];
// copy = [?,?,?,?,?,?,?,?,?,?]
char copy[ARRAY_SIZE];
int i;
// fill a part of "array" with a NUL terminated string
// "part" is not necessary half+1 of it, the only condition is: #part < ARRAY_SIZE
// such that we have at least one byte of garbage
for(i = 0;i < ARRAY_SIZE/2;i++){
// casting "i" is a bit "holier than the pope", admitted
array[i] = (char)i + '0';
}
array[i] = '[=10=]';
// array = ['0','1','2','3','4','[=10=]',?,?,?,?]
// "use" the array "array"
printf("array = %s\n",array);
// copy all of the elements of "array" to "copy" including
// the garbage at the end
for(i = 0;i < ARRAY_SIZE;i++){
copy[i] = array[i];
}
// copy = ['0','1','2','3','4','[=10=]',?,?,?,?]
// "use" the array "copy"
printf("copy = %s\n",copy);
// no further use of either "array" or "copy".
// obvious at the end of main() but meant generally, of course
exit(EXIT_SUCCESS);
}
标准中定义这些数组的段落在派生类型列表中:
6.2.5 Types
20 Any number of derived types can be constructed from the object and function types, as follows:
- An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type. The element type shall be complete whenever the array type is specified. Array types are characterized by their element type and by the number of elements in the array. An array type is said to be derived from its element type, and if its element type is T, the array type is sometimes called "array of T". The construction of an array type from an element type is called "array type derivation".
我的问题是:"nonempty set" 是否只是意味着声明中的 n
(其中 n
代表整数文字;它与 VLA 无关)T a[n]
必须大于零?
对于那些需要实际原因的人:在实时领域,明确定义的操作数量优于未知数量。由于必要的测量,它在大部分时间(假设输入的随机分布)也较慢,并且这种开销在嵌入区域中很重要。当电池需要保持足够的电量以 运行 几年时,每节省纳安安时就很重要。
是的,这意味着 ARRAY_SIZE 必须大于零。 在这个级别,您可能应该将优化留给编译器。 但是如果 ARRAY_SIZE 是一个定义的常量,您可以通过一个数组进行优化,该数组的元素大小与您的 CPU 寄存器相同。您的数组大小应该是寄存器大小的整数倍。 要进行更多优化,您应该深入研究汇编程序输出。
如果代码读取没有陷阱表示的类型的不确定值,标准对于保证或不保证什么是模糊的。如果一个类型有任何陷阱表示并且代码试图读取该类型的不确定值,则读取的值可能是陷阱表示,从而导致读取调用未定义的行为。但是,如果该类型没有任何陷阱表示,事情就不太清楚了。
要求代码不能复制数组元素,除非它已经初始化它,即使元素的类型没有陷阱表示,即使没有人关心副本的值,也会降低效率可以表达许多算法。另一方面,给出类似的东西:
struct fnord { unsigned char q; ... }
struct fnord x=foo[i];
doSomething(x.q);
...
doSomething(x.q);
不清楚是否需要编译器来确保相同的
在 foo[i]
持有不确定值的情况下,值将传递给两个函数调用。结构不允许有陷阱表示(unsigned char
以外的类型的成员可能,但复制整个结构是定义的行为,即使某些成员的底层存储持有其类型的陷阱表示)。另一方面,对 x
的写入可能被视为导致 x
持有不确定值,因此对 doSomething
的调用可能会收到不同的值。
如果标准指定了一种方法,可以读取没有陷阱表示的类型的不确定值以产生未指定的值,那将非常有帮助,但我不知道标准中有任何此类规范。