c++ 将 argv 读入 unsigned char 固定大小:分段错误

Posted

技术标签:

【中文标题】c++ 将 argv 读入 unsigned char 固定大小:分段错误【英文标题】:c++ reading argv into unsigned char fixed size: Segmentation fault 【发布时间】:2016-09-22 19:46:13 【问题描述】:

我正在尝试将命令行参数读入一个固定大小的无符号字符数组。我得到分段错误。

我的代码:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <memory.h>

unsigned char key[16]=;

int main(int argc, char** argv)
        std::cout << "Hello!" << std::endl;
        long a = atol(argv[1]);
        std::cout << a << std::endl;
        memcpy(key, (unsigned char*) a, sizeof key);
//      std::cout << sizeof key << std::endl;
//      for (int i = 0; i < 16; i++)
//              std::cout << (int) (key[i]) << std::endl;
        return 0;

我做错了什么?

调用程序:

编译:g++ main.cpp

执行:./a.out 128

【问题讨论】:

您的问题不完整。你怎么称呼你的程序? 你传递给 main 什么??? 可以是0到2^128之间的任意数字,对吧?!! @algoProg 解决此类问题的正确工具是您的调试器。 询问 Stack Overflow 之前,您应该逐行逐行检查您的代码。如需更多帮助,请阅读How to debug small programs (by Eric Lippert)。至少,您应该 [编辑] 您的问题,以包含一个重现您的问题的 Minimal, Complete, and Verifiable 示例,以及您在调试器中所做的观察。 为了它的价值,永远不要使用atol,因为还有另一个标准函数strtol具有相同的目的,但具有更好的错误处理能力。 【参考方案1】:

您获得 SEGV 是因为您的地址错误:您将值转换为地址。加上大小是目标之一,应该是源的大小

编译器发出警告,这绝不是好事,你应该考虑到它,因为这正是你的错误:

xxx.c:12:38: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]

     memcpy(key, (unsigned char*) a, sizeof key);
                                  ^

像这样修复它:

memcpy(key, &a, sizeof(a));

顺便说一句,您不必用 16 个字节声明 key。像这样分配它会更安全:

unsigned char key[sizeof(long)];

当你打印字节时,也要迭代直到sizeof(long),否则你最终只会打印垃圾字节。

这是使用uint64_t(来自stdint.h 的无符号64 位整数,可以精确控制大小)的修复建议,对key 进行零初始化并使用strtoll 进行解析:

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <memory.h>
#include <stdint.h>

unsigned char key[sizeof(uint64_t)]=0;

int main(int argc, char** argv)
        std::cout << "Hello!" << std::endl;
        uint64_t a = strtoll(argv[1],NULL,10);
        memcpy(key, &a, sizeof a);

      for (int i = 0; i < sizeof(key); i++)
              std::cout << (int) (key[i]) << std::endl;
        return 0;

(如果要处理签名,只需更改为int64_t

小端架​​构测试:

% a 10000000000000
Hello!
0
160
114
78
24
9
0
0

【讨论】:

嗨,Jean,这是我的问题。我要长长吗? @1201ProgramAlarm:不完全是,你是对的,谢谢。我错过了从整数到地址的转换! 修复了它。没有更多的错。我现在如何检查 key 中的值是什么?我的注释打印循环不起作用。编译器打印'?'。 嗨,我的密钥应该是 16 个字节。因此,如果一个数字小于 2^128,那么它应该在前面加上 0。这就是为什么我会这样。 long 中的 2^128 好运。即使unsigned long long 通常范围最大为 2^64-1【参考方案2】:

您似乎复制了太多数据。 我还为 memcpy 添加了一个 &a。

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <memory.h>

unsigned char key[16]=;

int main(int argc, char** argv)

   memset(key,0x0, sizeof(key));
   std::cout << "Hello!" << std::endl;
   long a = atol(argv[1]);
   std::cout << a << std::endl;

   // the size parameter needs to be the size of a
   // or the lesser of the size of key and a
   memcpy(key,(void *) &a, sizeof(a));
   std::cout << "size of key " << sizeof(key) << "\n";
   std::cout << "key " << key << "\n";
   for (int i = 0; i < 16; i++)
   std::cout << "   " << i << "    '"  << ((int) key[i]) << "'\n";
   return 0;

【讨论】:

以上是关于c++ 将 argv 读入 unsigned char 固定大小:分段错误的主要内容,如果未能解决你的问题,请参考以下文章

c++ 快速读入

将 char* 转换为 unsigned char*

c++任意读入一个英文字母,判断其是不是为元音字母?

快速读入(比scanf和getchar还快的读入方法)

如何将带有 unsigned char* 的结构从 C# 传递到 C++?

读入优化