小编Eug*_*Sh.的帖子

初始化指针时的字符串文字与char数组

灵感来自这个问题.

我们可以char用字符串文字初始化指针:

char *p = "ab";
Run Code Online (Sandbox Code Playgroud)

它完全没问题.人们可以认为它等同于以下内容:

char *p = {'a', 'b', '\0'};
Run Code Online (Sandbox Code Playgroud)

但显然事实并非如此.而且不仅因为字符串文字存储在只读内存中,而且即使通过字符串文字具有一种类型的char数组,并且初始化程序{...}具有char数组类型,两个声明的处理方式也不同,因为编译器是发出警告:

警告:标量初始化程序中的多余元素

在第二种情况下.这种行为的解释是什么?

更新:

此外,在后一种情况下,指针p将具有0x61(第一个数组元素的值'a')而不是存储器位置的值,使得编辑器在警告时仅采用初始化器的第一个元素并将其分配给p.

c arrays gcc

19
推荐指数
4
解决办法
5147
查看次数

如何在C或C++代码中分隔数字常量(即10,000)中的数字

Java允许数字常量中的数字按如下方式分隔:

int a = 1_000_000;
Run Code Online (Sandbox Code Playgroud)

C或C++是否有类似的结构?

c c++ literals

18
推荐指数
2
解决办法
952
查看次数

printf() std::string_view 的正确方法?

我是 C++17 和std::string_view. 我了解到它们不是空终止的,必须小心处理。

这是 printf() 的正确方法吗?

#include<string_view>
#include<cstdio>

int main()
{
    std::string_view sv{"Hallo!"};
    printf("=%*s=\n", static_cast<int>(sv.length()), sv.data());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

(或者将它与任何其他 printf 风格的函数一起使用?)

c++ printf string-view c++17

16
推荐指数
2
解决办法
6187
查看次数

将非`void`指针转换为`uintptr_t`,反之亦然

有两个相关的C标准规则:

C99标准,6.3.2.3:

指向void的指针可以转换为指向任何不完整或对象类型的指针.指向任何不完整或对象类型的指针可能会转换为指向void的指针并再次返回; 结果应该等于原始指针.

而且7.20.1.4:

以下类型指定一个无符号整数类型,其属性是任何有效的void指针都可以转换为此类型,然后转换回指向void的指针,结果将等于原始指针: uintptr_t

这意味着,以下代码符合:

int *p = NULL;
void *q = (void*)p;
uintptr_t s = (uintptr_t)q;
Run Code Online (Sandbox Code Playgroud)

但它真的需要两步演员吗?如果执行以下操作,编译器是否会执行隐式中间转换:

int *p = NULL;
uintptr_t s = (uintptr_t)p;
Run Code Online (Sandbox Code Playgroud)

(好吧,它可能会出现在大多数编译器上,但我的问题是关于标准符合性)

c standards pointers casting

13
推荐指数
1
解决办法
4012
查看次数

带花括号的字符串初始化程序

我遇到了一段代码,进行了以下初始化:

static const uint8_t s[] = {"Some string"};
Run Code Online (Sandbox Code Playgroud)

我希望它解释如下:右侧是一个char指针数组与单个元素匹配,指向字符串文字"Some string".而左边的部分是一个数组uint8_t.然后我期望的行为是第一个s接收字符串文字指针的截断值的元素,因此在下面的代码中引起意外行为,假设s是一个字符串.

我做了以下测试代码:

#include <stdint.h>
#include <stdio.h>

static const uint8_t s1[] = "String1";
static const uint8_t s2[] = { "String2" };
int main(void){

    printf("%p, %p\n", s1, s2);
    printf("%s, %s\n", s1, s2);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,它似乎没有发生.不仅代码将正常工作,而且拆装表明,无论s1s2被初始化为相同的方式对应的字符串.

这是gcc具体的吗?C语法是否允许将单个字符串文字带入{}并仍然将其解释为字符串文字?

c arrays string

10
推荐指数
2
解决办法
1238
查看次数

是`*(volatile T*)0x1234;`保证转换成读指令?

使用硬件时,有时需要从特定寄存器执行读取,丢弃实际值(例如,清除某些标志).一种方法是明确读取和丢弃值,例如:

int temp = *(volatile int*)0x1234; // 0x1234 is the register address
(void)temp;                          // To silence the "unused" warning
Run Code Online (Sandbox Code Playgroud)

另一种似乎有效的方法是:

*(volatile int*)0x1234;
Run Code Online (Sandbox Code Playgroud)

但这似乎并没有明显暗示访问,但它似乎转换为我检查的编译器上的一个.这是否由标准保证?

ARM GCC示例-O3:https: //arm.godbolt.org/z/9Vmt6n

void test(void)
{
    *(volatile int *)0x1234;
}
Run Code Online (Sandbox Code Playgroud)

翻译成

test():
        mov     r3, #4096
        ldr     r3, [r3, #564]
        bx      lr
Run Code Online (Sandbox Code Playgroud)

c volatile

10
推荐指数
1
解决办法
170
查看次数

NFS rootfs上的Busybox SUID

我正在从底部为Beagle Bone板构建一个Linux系统.我编译了vanilla内核并构建了一个基本的根文件系统busybox.系统使用U-boot启动,而rootfs它位于Linux PC上并通过NFS导出:

/path/to/rootfs  10.42.0.17(rw,wdelay,no_root_squash,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
Run Code Online (Sandbox Code Playgroud)

U-boot bootargs是:

bootargs console=ttyO0,115200n8 root=/dev/nfs rw nfsroot=${serverip}:/path/to/rootfs,v3,tcp ip=dhcp
Run Code Online (Sandbox Code Playgroud)

我在尝试su为非root用户工作时遇到了问题.为了解决这个问题,互联网上的人们建议设置二进制suidbusybox.这样做之后:

$ sudo chmod u+s busybox 
Run Code Online (Sandbox Code Playgroud)

并验证:

$ ls -la
...
-rwsr-xr-x  1 myuser myuser 1882976 Jan 13 21:47 busybox
...

$ stat -c "%a %n" busybox 
4755 busybox
Run Code Online (Sandbox Code Playgroud)

有些不对劲.内核正在启动并显示所有常用消息,但最后会卡住,并且不会login显示任何行.以下是启动顺序的最后几行:

[    3.776185] IP-Config: Complete:
[    3.779656]      device=eth0, hwaddr=c8:a0:30:c5:80:e9, ipaddr=10.42.0.17, mask=255.255.255.0, gw=10.42.0.1
[    3.789877]      host=10.42.0.17, domain=, nis-domain=(none)
[    3.795822]      bootserver=10.42.0.1, rootserver=10.42.0.1, rootpath=
[    3.802492]      nameserver0=10.42.0.1 …
Run Code Online (Sandbox Code Playgroud)

linux boot nfs rootfs embedded-linux

7
推荐指数
1
解决办法
539
查看次数

`printf("%. - 1s \n","foo")`是否调用未定义的行为?

根据标准:

每个转换规范由字符%引入.在%之后,以下顺序出现:

  • 零个或多个标志[...].
  • 可选的最小字段宽度.[...]
  • 一个可选的精度,它提供了为s转换写入的最大字节数.精度采用句点(.)后跟[...]可选十进制整数的形式;
  • 可选的长度修改器[...].+转换说明符[...].
  • 可选的最小字段宽度.[...]
  • 转换说明符[...].

后来:

如果省略精度,则采用负精度参数.

printf("%.-1s\n", "foo")根据我如何解释标准定义,我期望得到什么:

我从标准中得到的第二个引用表明我们可以传递一个负精度参数,并且这种精度会被忽略.

所以,printf("%.-1s\n", "foo")应该相当于printf("%s\n", "foo"),它会显示"foo\n"和返回4.

然而,这是printf("%.-1s\n", "foo")我使用的系统(osx)上的实际行为:

printf("%.-1s\n", "foo")显示" \n"和返回2.

这显然不同于我的预期.

  • 不知怎的,我对标准的解释错了吗?
  • 这种行为是不确定的?
  • 传递负精度(编辑:没有星号)实际上可能吗?

c standards printf undefined-behavior language-lawyer

7
推荐指数
1
解决办法
258
查看次数

C 中的字符串数组在内存中的样子如何?

我试图弄清楚 2d char 数组在内存中的样子。例如:

    char   c[][5]={"xa","ccc","bb","j","a","d"};

    printf("TEST: %u %u %u %u \n\n",c[0],*c[0],c[0]+1,*(c[0]+1));
Run Code Online (Sandbox Code Playgroud)

输出:

测试:3214246874 120 3214246875 97

c[0]=*(c+0) 是字符串“xa”,等于 3214246874,所以我猜 c[0] 是字符数组“xa”的地址。当我将 * 放入 c[0] 时,我得到 120,即 ascii 中的“x”。

所以我认为 c 数组中的第一个空格是字符 x 的地址。之后,我用 c[0]+1 尝试了同样的方法,它打印了下一个地址,然后我输入了 *,我得到了 ,97,它是 ASCII 中的“a”。

所以我假设数组 c 看起来像这样:

c[0]                              c[1]
------------------------------------------------------------------
| pointer to x | pointer to a ||| pointer to c | pointer to c | etc ...
----------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

但是我在网上搜索并没有找到任何证据来证明我的假设。

c arrays

6
推荐指数
1
解决办法
829
查看次数

在chip-8操作码FX65中增加I

在构建芯片 8 仿真器时,我遇到了芯片 8 信息的 2 个主要来源似乎不同的问题,这对整个芯片 8 解释器有影响。

一方面,我们有维基百科,它在操作码 FX65 下告诉我们

“用从地址 I 开始的内存中的值填充 V0 到 VX(包括 VX)。对于每个写入的值,I 增加 1。”

其中“对于写入的每个值I 增加 1。” 是重要的部分。

遵循此结果会产生以下代码:

for(int i = 0; i <= ((opcode & 0x0F00) >> 8); ++i) {
    V[i] = memory[I];
    ++I;
}
Run Code Online (Sandbox Code Playgroud)

另一方面,我们有cowgodchip-8 参考,几乎每个教程都链接到的参考,它告诉我们以下内容

“解释器从位置 I 开始的内存读取值到寄存器 V0 到 Vx。”

应用此逻辑会产生以下代码(这也是大多数芯片 8 实现使用的实现):

for(int i = 0; i <= ((opcode & 0x0F00) >> 8); ++i) {
    V[i] = memory[I …
Run Code Online (Sandbox Code Playgroud)

opcode chip-8

5
推荐指数
1
解决办法
261
查看次数