-2

I need to take an argument (argv[2]) and convert it to uint16_t type. How I can get this? I put a PORT in argument so I need to convert in uint16_t, I tried this:

uint16_t PORT;

PORT = argv[2];

but when I do

servaddr.sin_port = htons(PORT) 

I get

warning: assignment makes integer from pointer without a cast
Timer
  • 9
  • 4

3 Answers3

2

You can convert a char * to an int (and therefore, to a uint16_t) via the atoi() function:

#include <stdlib.h>

[...]

uint16_t PORT = atoi(argv[2]);
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • And what does `atoi()` return if you pass it the string `"XYZ"`? Never use `atoi()`. – Andrew Henle May 20 '20 at 15:11
  • In that case it returns 0. – Jeremy Friesner May 20 '20 at 15:12
  • @AndrewHenle sorry, but I get this : warning: conversion to ‘uint16_t {aka short unsigned int}’ from ‘int’ may alter its value – Timer May 20 '20 at 15:14
  • @JeremyFriesner No, [it's undefined behavior](https://port70.net/~nsz/c/c11/n1570.html#7.22.1): "The functions atof, atoi, atol, and atoll need not affect the value of the integer expression errno on an error. If the value of the result cannot be represented, the behavior is undefined." – Andrew Henle May 20 '20 at 15:15
  • @AndrewHenle well then, check if the string contains any non-numerical characters? How is misusing a function a deal-breaker for using it at all? – tb044491 May 20 '20 at 15:16
  • @Timer do uint16_t PORT = (uint16_t)atoi(argv[2]); ? – tb044491 May 20 '20 at 15:16
  • @AndrewHenle That refers to values that can not be represented. The lack of a value will cause UB, it will return 0. An out-of-range integer will cause UB. – Thomas Jager May 20 '20 at 15:17
  • @AndrewHenle perhaps you should post an answer with your recommended approach. That would be more productive than chivvying other answers with comments. – Jeremy Friesner May 20 '20 at 15:17
  • 1
    @JeremyFriesner Because I don't thing dropping the dupe hammer on a new user for duplicating [**How to use `strtoul` to parse string where zero may be valid?**](https://stackoverflow.com/questions/53764099/how-to-use-strtoul-to-parse-string-where-zero-may-be-valid) is a good learning experience. – Andrew Henle May 20 '20 at 15:21
0

You need to use the strtoul() function, a quick way would be like this:

errno = 0;
uint16_t PORT = strtoul(argv[2], NULL, 0);
if ( errno != 0 )
{
    //invalid input
}

A more robust way would to be use an intermediate unsigned long value and check that it contains a proper value for a 16-bit port.

See How to use strtoul to parse string where zero may be valid? for some more details.

Never use atoi(). It has no way to return any error condition, and if you pass it some invalid inputs it invokes undefined behavior.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Hello @Andrew Henle , with this I'm getting the next warning: warning: conversion to ‘uint16_t {aka short unsigned int}’ from ‘long unsigned int’ may alter its value – Timer May 20 '20 at 15:43
0

How to take a argv and convert it to uint16_t (?)

argv[i] may point to a string. The task is then to convert that string into a uint16_t.

OP's code fails as the below is more like taking the address of the string and converting it to a 16-bit value with potential truncation.

uint16_t PORT;
PORT = argv[2]; // poor code

Insure valid argv[2]

int main(int argc, char *argv[]) {
  if (argc <= 2) {
    fprintf(stderr, "argv[2] missing.\n");
    return EXIT_FAILURE;
  }
  ...

Handle non-numeric input

What should happen in cases like "abc", "123abc", "-123", "", " ", " 123 ", "123 abc", "123456", "123456789012345678901234567890", "0x123", "-0", "0.0", etc?

The usually goal is to be generous in allowing leading white-space and perhaps trailing WS (even though such WS is uncommon in argv[]). Complain about values outside the range [0...65535]. Complain about other non-integer numeric, non-white-space characters.

strtoul() is a good start with its well defined error handling.

atoi() fails to convert well to a uint16_t when input is not well formed or when int is 16-bit.

An attribute of strtoul() I do not like is that the '-' is applied after the conversion, so "-1" is OK input and returns a value of ULONG_MAX. I would rather detect that as an error. Since the range of long is always wider than uint16_t, I recommend strtol() if code should detect negative values as an error.

Sample

  char *endptr;
  errno = 0; 
  long value = strtol(argv[2], &endptr, 0);

  if (errno) { // This test not certainly needed here as later test will catch
    perror("argv[2] error");
    return EXIT_FAILURE;
  }

  if (argv[2] == endptr) { // No conversion happened
    fprintf(stderr, "argv[2] <%s> non-numeric\n", argv[2]);
    return EXIT_FAILURE;
  }

  if (value < 0 || value > UINT16_MAX) {
    fprintf(stderr, "argv[2] %ld outside uint16_t range\n", value);
    return EXIT_FAILURE;
  }

  while (isspace((unsigned char) *endptr)) {
    endptr++;
  }
  if (*endptr) {
    fprintf(stderr, "argv[2] <%s> trailing non-numeric text\n", argv[2]);
    return EXIT_FAILURE;
  }

  PORT = (uint16_t) value;  // Cast to quiet conversion warning

  printf("argv[2] --> %u success\n", PORT);
  return EXIT_SUCCESS;
}     

This lengthy code best incorporated as a helper function than replicated for each string to uint16_t. Yet I suspect OP will get to such functions later.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256