我遇到了一个常见的编程访谈问题:给定一个无符号整数列表,找到一个在列表中出现奇数次的整数.例如,如果给出列表:
{2,3,5,2,5,5,3}
Run Code Online (Sandbox Code Playgroud)
解决方案将是整数5,因为它在列表中出现3次而其他整数出现偶数次.
我的原始解决方案包括设置一个排序数组,然后迭代数组:对于每个奇数元素,我会添加整数,而对于每个偶数元素,我会减去; 结束总和是解决方案,因为其他整数将取消.
但是,我发现只需在每个元素上执行XOR就可以实现更高效的解决方案 - 您甚至不需要排序数组!也就是说:
2^3^5^2^5^5^3 = 5
Run Code Online (Sandbox Code Playgroud)
我从Discrete Structures类回忆起,我认为Associate Property适用于XOR操作,这就是为什么这个解决方案有效:
a^a = 0
Run Code Online (Sandbox Code Playgroud)
和:
a^a^a = a
Run Code Online (Sandbox Code Playgroud)
虽然我记得Associative Property适用于XOR,但是我很难找到特定于XOR的这个属性的逻辑证明(因特网上的大多数逻辑证据似乎更侧重于AND和OR操作).有谁知道为什么关联属性适用于XOR操作?
我怀疑它涉及包含AND和/或OR的XOR身份.
我最近学会了如何编写简单的字符驱动程序,在玩这些代码时,我注意到我的C99代码中出现了很多以下的GCC警告:
warning: ISO C90 forbids mixed declarations and code
Run Code Online (Sandbox Code Playgroud)
我假设这是因为主Linux内核Makefile设置为使用非C99标准进行编译.我在附近搜索我在stackoverflow上找到了这个答案:如何使用make和编译为C99?
所以我自然在我的Makefile中尝试了以下内容:
ccflags-y := -std=gnu99
Run Code Online (Sandbox Code Playgroud)
不幸的是,这并没有使GCC警告无声.我检查了详细的输出make并验证了GCC确实-std=gnu99在最后加上了; 所以我有点困惑.
如何使用该-std=gnu99选项正确编译Linux内核模块?
编辑:
我注意到GCC输出显示了这个选项:-Wdeclaration-after-statement.这是为什么即使有-std=gnu99选项我也会得到警告?
我有一个简单的sysfs设备属性,显示在我的sysfs目录下,并在调用时read返回一个kernelspace变量的值.我想调用poll此属性以允许我的用户空间线程阻塞,直到属性显示的值发生更改.
我的问题是poll似乎没有阻止我的属性 - POLLPRI即使属性显示的值没有改变,它仍然会返回.实际上,我sysfs_notify在内核模块中根本没有调用,但用户空间调用poll仍然没有阻塞.
也许我应该检查比其他东西返回值POLLPRI-但根据文档中的Linux内核,sysfs_poll应该返回POLLERR|POLLPRI:
/* ... When the content changes (assuming the
* manager for the kobject supports notification), poll will
* return POLLERR|POLLPRI ...
*/
Run Code Online (Sandbox Code Playgroud)
有什么我忘了做的事poll吗?
device属性位于:/ sys/class/vilhelm/foo/blah.
我加载了一个名为foo的内核模块,它注册了一个设备,并创建了一个类和这个设备属性.
名为bar的用户空间应用程序生成一个调用poll设备属性的线程,检查POLLPRI.
poll返回正数,POLLPRI则返回.fopen和fscan从设备属性文件中读取值.据我所知,USER_HZ在Linux 2.6中添加了常量来解决HZ用户空间价值期望所引起的问题:在以前版本的Linux中,更改HZ值可能会导致用户空间应用程序中的值无意中缩放.
我对USER_HZ常量如何解决这个缩放问题感到困惑.例如,假设用户空间应用程序将jiffies转换为秒:
long MY_HZ = sysconf(_SC_CLK_TCK);
/* num_jiffies acquired from /proc but
* simplified to 1000 here for clarity */
long num_jiffies = 1000;
long num_seconds = num_jiffies / MY_HZ;
Run Code Online (Sandbox Code Playgroud)
由于用户空间应用程序HZ通过sysconf调用确定值,这不会阻止扩展问题吗?
另一方面,如果用户空间应用程序确实将HZ值硬编码到其源中,那么USER_HZ常量如何防止扩展问题 - 用户空间应用程序将使用其硬编码常量而不是系统USER_HZ,并且不能保证硬编码常数匹配USER_HZ?
此外,用户空间(例如/proc)已经缩放到的所有时钟滴答值是否可用USER_HZ?用户空间程序如何知道jiffies中的值是缩放HZ还是USER_HZ?
这是Quake III Arena的快速反平方根实现:
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// …Run Code Online (Sandbox Code Playgroud) 我知道何时使用补鞋匠列表(例如列出在程序集中修改的寄存器,以便它不被选择用作输入寄存器等),但我无法绕过早期约束条件&.如果列出输出,那是否已经意味着输入不能使用所选寄存器(除了匹配数字约束)?
例如:
asm(
"movl $1, %0;"
"addl $3, %0;"
"addl $4, %1;"
"addl %1, %0;"
: "=g"(num_out)
: "g"(num_in)
:
);
Run Code Online (Sandbox Code Playgroud)
会&甚至需要为输出变量?编译器应该知道为输出选择的寄存器,因此知道不要将它用于输入.
在32位系统上,ftell如果以二进制模式打开的文件的当前位置指示符超过2GB点,会返回什么?在C99标准中,这是未定义的行为,因为ftell必须返回一个long int(最大值为2**31-1)?
来自GNU C编程教程:
该
fgets("文件中获取字符串")功能类似于获取功能.这个函数已被弃用 - 这意味着它已经过时,强烈建议你不要使用它 - 因为它很危险.这很危险,因为如果输入数据包含空字符,则无法分辨.fgets除非您知道数据不能包含null,否则请勿使用.不要使用它来读取用户编辑的文件,因为如果用户插入空字符,您应该正确处理它或打印清晰的错误消息.如果可以,请始终使用getline或getdelim代替fgets.
我觉得这个fgets功能在遇到a \0或者时会停止\n; 为什么当fgets应该正确处理输入时,这个手册页建议空字节是"危险的" ?此外,之间有什么区别getline和fgets,是fgets真正视为功能过时的C99或将来的C标准?
我正在尝试在两个模块之间共享一个全局变量,以便了解如何EXPORT_SYMBOL正确使用宏,但是Invalid paramaters当我尝试插入第二个模块时,我不断收到错误.
在第一个模块中foo.c:
#include <linux/module.h>
#include <linux/kernel.h>
extern unsigned myvar;
unsigned myvar = 42;
EXPORT_SYMBOL(myvar);
static int __init foo_init(void){
printk(KERN_INFO "HELLO FROM MODULE 1");
return 0;
}
static void __exit foo_exit(void){
printk(KERN_INFO "BYE FROM MODULE 1");
}
module_init(foo_init);
module_exit(foo_exit);
MODULE_LICENSE("GPL");
Run Code Online (Sandbox Code Playgroud)
在第二个模块中bar.c:
#include <linux/module.h>
#include <linux/kernel.h>
extern unsigned myvar;
static int __init bar_init(void){
printk(KERN_INFO "HELLO FROM MODULE 2");
printk(KERN_INFO "myvar: %u", myvar);
return 0;
}
static void __exit bar_exit(void){
printk(KERN_INFO "BYE FROM MODULE …Run Code Online (Sandbox Code Playgroud) 我想定义一个多维C字符串数组,该数组由多个字符串文字初始化。在C语言中,我将执行以下操作:
#include <stdio.h>
const char *strArr[2][1] = { {"foo"}, {""}};
int main(void) {
printf("%p\t%p\n", strArr[0][0], strArr[1][0]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在以下位置编译gcc -std=c18 -pedantic test.c并执行结果:
#include <stdio.h>
const char *strArr[2][1] = { {"foo"}, {""}};
int main(void) {
printf("%p\t%p\n", strArr[0][0], strArr[1][0]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如我所料,空字符串文字strArr[1][0]会衰减为有效的指针。
但是,当我在C ++中尝试相同的代码时:
#include <cstdio>
const char *strArr[2][1] = { {"foo"}, {""}};
int main(void) {
printf("%p\t%p\n", strArr[0][0], strArr[1][0]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在以下位置编译g++ -std=c++17 -pedantic test.cpp并执行结果:
$ ./a.out
0x55d95410f004 0x55d95410f008 …Run Code Online (Sandbox Code Playgroud)